Mercurial > projects > dwt-addons
annotate dwtx/jface/text/templates/persistence/TemplateStore.d @ 162:1a5b8f8129df
...
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Mon, 08 Sep 2008 00:51:37 +0200 |
parents | f70d9508c95c |
children | 284c2e810329 |
rev | line source |
---|---|
129 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2006 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.persistence.TemplateStore; | |
14 | |
131 | 15 import dwtx.jface.text.templates.persistence.TemplatePersistenceData; // packageimport |
16 import dwtx.jface.text.templates.persistence.TemplateReaderWriter; // packageimport | |
17 import dwtx.jface.text.templates.persistence.TemplatePersistenceMessages; // packageimport | |
18 | |
129 | 19 import dwt.dwthelper.utils; |
153
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
148
diff
changeset
|
20 import dwtx.dwtxhelper.Collection; |
f70d9508c95c
Fix java Collection imports
Frank Benoit <benoit@tionex.de>
parents:
148
diff
changeset
|
21 |
129 | 22 import dwtx.core.runtime.Assert; |
23 import dwtx.jface.preference.IPersistentPreferenceStore; | |
24 import dwtx.jface.preference.IPreferenceStore; | |
25 import dwtx.jface.text.templates.ContextTypeRegistry; | |
26 import dwtx.jface.text.templates.Template; | |
27 import dwtx.jface.text.templates.TemplateException; | |
28 import dwtx.jface.util.IPropertyChangeListener; | |
29 import dwtx.jface.util.PropertyChangeEvent; | |
30 | |
31 /** | |
32 * A collection of templates. Clients may instantiate this class. In order to | |
33 * load templates contributed using the <code>dwtx.ui.editors.templates</code> | |
34 * extension point, use a <code>ContributionTemplateStore</code>. | |
35 * | |
36 * @since 3.0 | |
37 */ | |
38 public class TemplateStore { | |
39 /** The stored templates. */ | |
146 | 40 private const List fTemplates= new ArrayList(); |
129 | 41 /** The preference store. */ |
42 private IPreferenceStore fPreferenceStore; | |
43 /** | |
44 * The key into <code>fPreferenceStore</code> the value of which holds custom templates | |
45 * encoded as XML. | |
46 */ | |
47 private String fKey; | |
48 /** | |
49 * The context type registry, or <code>null</code> if all templates regardless | |
50 * of context type should be loaded. | |
51 */ | |
52 private ContextTypeRegistry fRegistry; | |
53 /** | |
54 * Set to <code>true</code> if property change events should be ignored (e.g. during writing | |
55 * to the preference store). | |
148 | 56 * |
129 | 57 * @since 3.2 |
58 */ | |
59 private bool fIgnorePreferenceStoreChanges= false; | |
60 /** | |
61 * The property listener, if any is registered, <code>null</code> otherwise. | |
148 | 62 * |
129 | 63 * @since 3.2 |
64 */ | |
65 private IPropertyChangeListener fPropertyListener; | |
66 | |
67 | |
68 /** | |
69 * Creates a new template store. | |
70 * | |
71 * @param store the preference store in which to store custom templates | |
72 * under <code>key</code> | |
73 * @param key the key into <code>store</code> where to store custom | |
74 * templates | |
75 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
76 public this(IPreferenceStore store, String key) { |
129 | 77 Assert.isNotNull(store); |
78 Assert.isNotNull(key); | |
79 fPreferenceStore= store; | |
80 fKey= key; | |
81 } | |
82 | |
83 /** | |
84 * Creates a new template store with a context type registry. Only templates | |
85 * that specify a context type contained in the registry will be loaded by | |
86 * this store if the registry is not <code>null</code>. | |
87 * | |
88 * @param registry a context type registry, or <code>null</code> if all | |
89 * templates should be loaded | |
90 * @param store the preference store in which to store custom templates | |
91 * under <code>key</code> | |
92 * @param key the key into <code>store</code> where to store custom | |
93 * templates | |
94 */ | |
133
7d818bd32d63
Fix ctors to this with gvim regexp
Frank Benoit <benoit@tionex.de>
parents:
131
diff
changeset
|
95 public this(ContextTypeRegistry registry, IPreferenceStore store, String key) { |
129 | 96 this(store, key); |
97 fRegistry= registry; | |
98 } | |
99 | |
100 /** | |
101 * Loads the templates from contributions and preferences. | |
102 * | |
103 * @throws IOException if loading fails. | |
104 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
105 public void load() { |
129 | 106 fTemplates.clear(); |
107 loadContributedTemplates(); | |
108 loadCustomTemplates(); | |
109 } | |
148 | 110 |
129 | 111 /** |
112 * Starts listening for property changes on the preference store. If the configured preference | |
113 * key changes, the template store is {@link #load() reloaded}. Call | |
114 * {@link #stopListeningForPreferenceChanges()} to remove any listener and stop the | |
115 * auto-updating behavior. | |
148 | 116 * |
129 | 117 * @since 3.2 |
118 */ | |
119 public final void startListeningForPreferenceChanges() { | |
120 if (fPropertyListener is null) { | |
135 | 121 fPropertyListener= new class() IPropertyChangeListener { |
129 | 122 public void propertyChange(PropertyChangeEvent event) { |
123 /* | |
124 * Don't load if we are in the process of saving ourselves. We are in sync anyway after the | |
125 * save operation, and clients may trigger reloading by listening to preference store | |
126 * updates. | |
127 */ | |
128 if (!fIgnorePreferenceStoreChanges && fKey.equals(event.getProperty())) | |
129 try { | |
130 load(); | |
131 } catch (IOException x) { | |
132 handleException(x); | |
133 } | |
134 } | |
135 }; | |
136 fPreferenceStore.addPropertyChangeListener(fPropertyListener); | |
137 } | |
148 | 138 |
129 | 139 } |
148 | 140 |
129 | 141 /** |
142 * Stops the auto-updating behavior started by calling | |
143 * {@link #startListeningForPreferenceChanges()}. | |
148 | 144 * |
129 | 145 * @since 3.2 |
146 */ | |
147 public final void stopListeningForPreferenceChanges() { | |
148 if (fPropertyListener !is null) { | |
149 fPreferenceStore.removePropertyChangeListener(fPropertyListener); | |
150 fPropertyListener= null; | |
151 } | |
152 } | |
148 | 153 |
129 | 154 /** |
155 * Handles an {@link IOException} thrown during reloading the preferences due to a preference | |
156 * store update. The default is to write to stderr. | |
148 | 157 * |
129 | 158 * @param x the exception |
159 * @since 3.2 | |
160 */ | |
161 protected void handleException(IOException x) { | |
162 x.printStackTrace(); | |
163 } | |
164 | |
165 /** | |
166 * Hook method to load contributed templates. Contributed templates are superseded | |
167 * by customized versions of user added templates stored in the preferences. | |
168 * <p> | |
169 * The default implementation does nothing.</p> | |
170 * | |
171 * @throws IOException if loading fails | |
172 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
173 protected void loadContributedTemplates() { |
129 | 174 } |
175 | |
176 /** | |
177 * Adds a template to the internal store. The added templates must have | |
178 * a unique id. | |
179 * | |
180 * @param data the template data to add | |
181 */ | |
182 protected void internalAdd(TemplatePersistenceData data) { | |
183 if (!data.isCustom()) { | |
184 // check if the added template is not a duplicate id | |
185 String id= data.getId(); | |
186 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 187 TemplatePersistenceData d2= cast(TemplatePersistenceData) it.next(); |
129 | 188 if (d2.getId() !is null && d2.getId().equals(id)) |
189 return; | |
190 } | |
191 fTemplates.add(data); | |
192 } | |
193 } | |
194 | |
195 /** | |
196 * Saves the templates to the preferences. | |
197 * | |
198 * @throws IOException if the templates cannot be written | |
199 */ | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
200 public void save() { |
129 | 201 ArrayList custom= new ArrayList(); |
202 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 203 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
129 | 204 if (data.isCustom() && !(data.isUserAdded() && data.isDeleted())) // don't save deleted user-added templates |
205 custom.add(data); | |
206 } | |
207 | |
208 StringWriter output= new StringWriter(); | |
209 TemplateReaderWriter writer= new TemplateReaderWriter(); | |
162 | 210 writer.save(arraycast!(TemplatePersistenceData)( custom.toArray()), output); |
129 | 211 |
212 fIgnorePreferenceStoreChanges= true; | |
213 try { | |
214 fPreferenceStore.setValue(fKey, output.toString()); | |
138 | 215 if ( cast(IPersistentPreferenceStore)fPreferenceStore ) |
134 | 216 (cast(IPersistentPreferenceStore)fPreferenceStore).save(); |
129 | 217 } finally { |
218 fIgnorePreferenceStoreChanges= false; | |
219 } | |
220 } | |
221 | |
222 /** | |
223 * Adds a template encapsulated in its persistent form. | |
224 * | |
225 * @param data the template to add | |
226 */ | |
227 public void add(TemplatePersistenceData data) { | |
228 | |
229 if (!validateTemplate(data.getTemplate())) | |
230 return; | |
231 | |
232 if (data.isUserAdded()) { | |
233 fTemplates.add(data); | |
234 } else { | |
235 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 236 TemplatePersistenceData d2= cast(TemplatePersistenceData) it.next(); |
129 | 237 if (d2.getId() !is null && d2.getId().equals(data.getId())) { |
238 d2.setTemplate(data.getTemplate()); | |
239 d2.setDeleted(data.isDeleted()); | |
240 d2.setEnabled(data.isEnabled()); | |
241 return; | |
242 } | |
243 } | |
244 | |
245 // add an id which is not contributed as add-on | |
246 if (data.getTemplate() !is null) { | |
247 TemplatePersistenceData newData= new TemplatePersistenceData(data.getTemplate(), data.isEnabled()); | |
248 fTemplates.add(newData); | |
249 } | |
250 } | |
251 } | |
252 | |
253 /** | |
254 * Removes a template from the store. | |
255 * | |
256 * @param data the template to remove | |
257 */ | |
148 | 258 public void delete_(TemplatePersistenceData data) { |
129 | 259 if (data.isUserAdded()) |
260 fTemplates.remove(data); | |
261 else | |
262 data.setDeleted(true); | |
263 } | |
264 | |
265 /** | |
266 * Restores all contributed templates that have been deleted. | |
267 */ | |
268 public void restoreDeleted() { | |
269 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 270 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
129 | 271 if (data.isDeleted()) |
272 data.setDeleted(false); | |
273 } | |
274 } | |
275 | |
276 /** | |
277 * Deletes all user-added templates and reverts all contributed templates. | |
278 */ | |
279 public void restoreDefaults() { | |
280 try { | |
281 fIgnorePreferenceStoreChanges= true; | |
282 fPreferenceStore.setToDefault(fKey); | |
283 } finally { | |
284 fIgnorePreferenceStoreChanges= false; | |
285 } | |
286 try { | |
287 load(); | |
288 } catch (IOException x) { | |
289 // can't log from jface-text | |
290 x.printStackTrace(); | |
291 } | |
292 } | |
293 | |
294 /** | |
295 * Returns all enabled templates. | |
296 * | |
297 * @return all enabled templates | |
298 */ | |
299 public Template[] getTemplates() { | |
300 return getTemplates(null); | |
301 } | |
302 | |
303 /** | |
304 * Returns all enabled templates for the given context type. | |
305 * | |
306 * @param contextTypeId the id of the context type of the requested templates, or <code>null</code> if all templates should be returned | |
307 * @return all enabled templates for the given context type | |
308 */ | |
309 public Template[] getTemplates(String contextTypeId) { | |
310 List templates= new ArrayList(); | |
311 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 312 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
129 | 313 if (data.isEnabled() && !data.isDeleted() && (contextTypeId is null || contextTypeId.equals(data.getTemplate().getContextTypeId()))) |
314 templates.add(data.getTemplate()); | |
315 } | |
316 | |
162 | 317 return arraycast!(Template)( templates.toArray()); |
129 | 318 } |
319 | |
320 /** | |
321 * Returns the first enabled template that matches the name. | |
322 * | |
323 * @param name the name of the template searched for | |
324 * @return the first enabled template that matches both name and context type id, or <code>null</code> if none is found | |
325 */ | |
326 public Template findTemplate(String name) { | |
327 return findTemplate(name, null); | |
328 } | |
329 | |
330 /** | |
331 * Returns the first enabled template that matches both name and context type id. | |
332 * | |
333 * @param name the name of the template searched for | |
334 * @param contextTypeId the context type id to clip unwanted templates, or <code>null</code> if any context type is OK | |
335 * @return the first enabled template that matches both name and context type id, or <code>null</code> if none is found | |
336 */ | |
337 public Template findTemplate(String name, String contextTypeId) { | |
338 Assert.isNotNull(name); | |
339 | |
340 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 341 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
145 | 342 Template template_= data.getTemplate(); |
129 | 343 if (data.isEnabled() && !data.isDeleted() |
145 | 344 && (contextTypeId is null || contextTypeId.equals(template_.getContextTypeId())) |
345 && name.equals(template_.getName())) | |
346 return template_; | |
129 | 347 } |
348 | |
349 return null; | |
350 } | |
351 | |
352 /** | |
353 * Returns the first enabled template that matches the given template id. | |
354 * | |
355 * @param id the id of the template searched for | |
356 * @return the first enabled template that matches id, or <code>null</code> if none is found | |
357 * @since 3.1 | |
358 */ | |
359 public Template findTemplateById(String id) { | |
360 TemplatePersistenceData data= getTemplateData(id); | |
361 if (data !is null && !data.isDeleted()) | |
362 return data.getTemplate(); | |
363 | |
364 return null; | |
365 } | |
366 | |
367 /** | |
368 * Returns all template data. | |
369 * | |
370 * @param includeDeleted whether to include deleted data | |
371 * @return all template data, whether enabled or not | |
372 */ | |
373 public TemplatePersistenceData[] getTemplateData(bool includeDeleted) { | |
374 List datas= new ArrayList(); | |
375 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 376 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
129 | 377 if (includeDeleted || !data.isDeleted()) |
378 datas.add(data); | |
379 } | |
380 | |
162 | 381 return arraycast!(TemplatePersistenceData)( datas.toArray()); |
129 | 382 } |
383 | |
384 /** | |
385 * Returns the template data of the template with id <code>id</code> or | |
386 * <code>null</code> if no such template can be found. | |
387 * | |
388 * @param id the id of the template data | |
389 * @return the template data of the template with id <code>id</code> or <code>null</code> | |
390 * @since 3.1 | |
391 */ | |
392 public TemplatePersistenceData getTemplateData(String id) { | |
393 Assert.isNotNull(id); | |
394 for (Iterator it= fTemplates.iterator(); it.hasNext();) { | |
134 | 395 TemplatePersistenceData data= cast(TemplatePersistenceData) it.next(); |
129 | 396 if (id.equals(data.getId())) |
397 return data; | |
398 } | |
399 | |
400 return null; | |
401 } | |
402 | |
136
6dcb0baaa031
Regex removal of throws decls, some instanceof
Frank Benoit <benoit@tionex.de>
parents:
135
diff
changeset
|
403 private void loadCustomTemplates() { |
129 | 404 String pref= fPreferenceStore.getString(fKey); |
405 if (pref !is null && pref.trim().length() > 0) { | |
406 Reader input= new StringReader(pref); | |
407 TemplateReaderWriter reader= new TemplateReaderWriter(); | |
408 TemplatePersistenceData[] datas= reader.read(input); | |
409 for (int i= 0; i < datas.length; i++) { | |
410 TemplatePersistenceData data= datas[i]; | |
411 add(data); | |
412 } | |
413 } | |
414 } | |
415 | |
416 /** | |
417 * Validates a template against the context type registered in the context | |
418 * type registry. Returns always <code>true</code> if no registry is | |
419 * present. | |
420 * | |
421 * @param template the template to validate | |
422 * @return <code>true</code> if validation is successful or no context | |
423 * type registry is specified, <code>false</code> if validation | |
424 * fails | |
425 */ | |
145 | 426 private bool validateTemplate(Template template_) { |
427 String contextTypeId= template_.getContextTypeId(); | |
129 | 428 if (contextExists(contextTypeId)) { |
429 if (fRegistry !is null) | |
430 try { | |
145 | 431 fRegistry.getContextType(contextTypeId).validate(template_.getPattern()); |
129 | 432 } catch (TemplateException e) { |
433 return false; | |
434 } | |
435 return true; | |
436 } | |
437 | |
438 return false; | |
439 } | |
440 | |
441 /** | |
442 * Returns <code>true</code> if a context type id specifies a valid context type | |
443 * or if no context type registry is present. | |
444 * | |
445 * @param contextTypeId the context type id to look for | |
446 * @return <code>true</code> if the context type specified by the id | |
447 * is present in the context type registry, or if no registry is | |
448 * specified | |
449 */ | |
450 private bool contextExists(String contextTypeId) { | |
451 return contextTypeId !is null && (fRegistry is null || fRegistry.getContextType(contextTypeId) !is null); | |
452 } | |
453 | |
454 /** | |
455 * Returns the registry. | |
456 * | |
457 * @return Returns the registry | |
458 */ | |
459 protected final ContextTypeRegistry getRegistry() { | |
460 return fRegistry; | |
461 } | |
462 } | |
463 |