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