KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jface > text > templates > persistence > TemplateStore


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  *******************************************************************************/

11 package org.eclipse.jface.text.templates.persistence;
12
13 import java.io.IOException JavaDoc;
14 import java.io.Reader JavaDoc;
15 import java.io.StringReader JavaDoc;
16 import java.io.StringWriter JavaDoc;
17 import java.util.ArrayList JavaDoc;
18 import java.util.Iterator JavaDoc;
19 import java.util.List JavaDoc;
20
21 import org.eclipse.core.runtime.Assert;
22
23 import org.eclipse.jface.preference.IPersistentPreferenceStore;
24 import org.eclipse.jface.preference.IPreferenceStore;
25 import org.eclipse.jface.util.IPropertyChangeListener;
26 import org.eclipse.jface.util.PropertyChangeEvent;
27
28 import org.eclipse.jface.text.templates.ContextTypeRegistry;
29 import org.eclipse.jface.text.templates.Template;
30 import org.eclipse.jface.text.templates.TemplateException;
31
32 /**
33  * A collection of templates. Clients may instantiate this class. In order to
34  * load templates contributed using the <code>org.eclipse.ui.editors.templates</code>
35  * extension point, use a <code>ContributionTemplateStore</code>.
36  *
37  * @since 3.0
38  */

39 public class TemplateStore {
40     /** The stored templates. */
41     private final List JavaDoc fTemplates= new ArrayList JavaDoc();
42     /** The preference store. */
43     private IPreferenceStore fPreferenceStore;
44     /**
45      * The key into <code>fPreferenceStore</code> the value of which holds custom templates
46      * encoded as XML.
47      */

48     private String JavaDoc fKey;
49     /**
50      * The context type registry, or <code>null</code> if all templates regardless
51      * of context type should be loaded.
52      */

53     private ContextTypeRegistry fRegistry;
54     /**
55      * Set to <code>true</code> if property change events should be ignored (e.g. during writing
56      * to the preference store).
57      *
58      * @since 3.2
59      */

60     private boolean fIgnorePreferenceStoreChanges= false;
61     /**
62      * The property listener, if any is registered, <code>null</code> otherwise.
63      *
64      * @since 3.2
65      */

66     private IPropertyChangeListener fPropertyListener;
67
68
69     /**
70      * Creates a new template store.
71      *
72      * @param store the preference store in which to store custom templates
73      * under <code>key</code>
74      * @param key the key into <code>store</code> where to store custom
75      * templates
76      */

77     public TemplateStore(IPreferenceStore store, String JavaDoc key) {
78         Assert.isNotNull(store);
79         Assert.isNotNull(key);
80         fPreferenceStore= store;
81         fKey= key;
82     }
83
84     /**
85      * Creates a new template store with a context type registry. Only templates
86      * that specify a context type contained in the registry will be loaded by
87      * this store if the registry is not <code>null</code>.
88      *
89      * @param registry a context type registry, or <code>null</code> if all
90      * templates should be loaded
91      * @param store the preference store in which to store custom templates
92      * under <code>key</code>
93      * @param key the key into <code>store</code> where to store custom
94      * templates
95      */

96     public TemplateStore(ContextTypeRegistry registry, IPreferenceStore store, String JavaDoc key) {
97         this(store, key);
98         fRegistry= registry;
99     }
100
101     /**
102      * Loads the templates from contributions and preferences.
103      *
104      * @throws IOException if loading fails.
105      */

106     public void load() throws IOException JavaDoc {
107         fTemplates.clear();
108         loadContributedTemplates();
109         loadCustomTemplates();
110     }
111     
112     /**
113      * Starts listening for property changes on the preference store. If the configured preference
114      * key changes, the template store is {@link #load() reloaded}. Call
115      * {@link #stopListeningForPreferenceChanges()} to remove any listener and stop the
116      * auto-updating behavior.
117      *
118      * @since 3.2
119      */

120     public final void startListeningForPreferenceChanges() {
121         if (fPropertyListener == null) {
122             fPropertyListener= new IPropertyChangeListener() {
123                 public void propertyChange(PropertyChangeEvent event) {
124                     /*
125                      * Don't load if we are in the process of saving ourselves. We are in sync anyway after the
126                      * save operation, and clients may trigger reloading by listening to preference store
127                      * updates.
128                      */

129                     if (!fIgnorePreferenceStoreChanges && fKey.equals(event.getProperty()))
130                         try {
131                             load();
132                         } catch (IOException JavaDoc x) {
133                             handleException(x);
134                         }
135                 }
136             };
137             fPreferenceStore.addPropertyChangeListener(fPropertyListener);
138         }
139         
140     }
141     
142     /**
143      * Stops the auto-updating behavior started by calling
144      * {@link #startListeningForPreferenceChanges()}.
145      *
146      * @since 3.2
147      */

148     public final void stopListeningForPreferenceChanges() {
149         if (fPropertyListener != null) {
150             fPreferenceStore.removePropertyChangeListener(fPropertyListener);
151             fPropertyListener= null;
152         }
153     }
154     
155     /**
156      * Handles an {@link IOException} thrown during reloading the preferences due to a preference
157      * store update. The default is to write to stderr.
158      *
159      * @param x the exception
160      * @since 3.2
161      */

162     protected void handleException(IOException JavaDoc x) {
163         x.printStackTrace();
164     }
165
166     /**
167      * Hook method to load contributed templates. Contributed templates are superseded
168      * by customized versions of user added templates stored in the preferences.
169      * <p>
170      * The default implementation does nothing.</p>
171      *
172      * @throws IOException if loading fails
173      */

174     protected void loadContributedTemplates() throws IOException JavaDoc {
175     }
176
177     /**
178      * Adds a template to the internal store. The added templates must have
179      * a unique id.
180      *
181      * @param data the template data to add
182      */

183     protected void internalAdd(TemplatePersistenceData data) {
184         if (!data.isCustom()) {
185             // check if the added template is not a duplicate id
186
String JavaDoc id= data.getId();
187             for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
188                 TemplatePersistenceData d2= (TemplatePersistenceData) it.next();
189                 if (d2.getId() != null && d2.getId().equals(id))
190                     return;
191             }
192             fTemplates.add(data);
193         }
194     }
195
196     /**
197      * Saves the templates to the preferences.
198      *
199      * @throws IOException if the templates cannot be written
200      */

201     public void save() throws IOException JavaDoc {
202         ArrayList JavaDoc custom= new ArrayList JavaDoc();
203         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
204             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
205             if (data.isCustom() && !(data.isUserAdded() && data.isDeleted())) // don't save deleted user-added templates
206
custom.add(data);
207         }
208
209         StringWriter JavaDoc output= new StringWriter JavaDoc();
210         TemplateReaderWriter writer= new TemplateReaderWriter();
211         writer.save((TemplatePersistenceData[]) custom.toArray(new TemplatePersistenceData[custom.size()]), output);
212
213         fIgnorePreferenceStoreChanges= true;
214         try {
215             fPreferenceStore.setValue(fKey, output.toString());
216             if (fPreferenceStore instanceof IPersistentPreferenceStore)
217                 ((IPersistentPreferenceStore)fPreferenceStore).save();
218         } finally {
219             fIgnorePreferenceStoreChanges= false;
220         }
221     }
222
223     /**
224      * Adds a template encapsulated in its persistent form.
225      *
226      * @param data the template to add
227      */

228     public void add(TemplatePersistenceData data) {
229
230         if (!validateTemplate(data.getTemplate()))
231             return;
232
233         if (data.isUserAdded()) {
234             fTemplates.add(data);
235         } else {
236             for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
237                 TemplatePersistenceData d2= (TemplatePersistenceData) it.next();
238                 if (d2.getId() != null && d2.getId().equals(data.getId())) {
239                     d2.setTemplate(data.getTemplate());
240                     d2.setDeleted(data.isDeleted());
241                     d2.setEnabled(data.isEnabled());
242                     return;
243                 }
244             }
245
246             // add an id which is not contributed as add-on
247
if (data.getTemplate() != null) {
248                 TemplatePersistenceData newData= new TemplatePersistenceData(data.getTemplate(), data.isEnabled());
249                 fTemplates.add(newData);
250             }
251         }
252     }
253
254     /**
255      * Removes a template from the store.
256      *
257      * @param data the template to remove
258      */

259     public void delete(TemplatePersistenceData data) {
260         if (data.isUserAdded())
261             fTemplates.remove(data);
262         else
263             data.setDeleted(true);
264     }
265
266     /**
267      * Restores all contributed templates that have been deleted.
268      */

269     public void restoreDeleted() {
270         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
271             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
272             if (data.isDeleted())
273                 data.setDeleted(false);
274         }
275     }
276
277     /**
278      * Deletes all user-added templates and reverts all contributed templates.
279      */

280     public void restoreDefaults() {
281         try {
282             fIgnorePreferenceStoreChanges= true;
283             fPreferenceStore.setToDefault(fKey);
284         } finally {
285             fIgnorePreferenceStoreChanges= false;
286         }
287         try {
288             load();
289         } catch (IOException JavaDoc x) {
290             // can't log from jface-text
291
x.printStackTrace();
292         }
293     }
294
295     /**
296      * Returns all enabled templates.
297      *
298      * @return all enabled templates
299      */

300     public Template[] getTemplates() {
301         return getTemplates(null);
302     }
303
304     /**
305      * Returns all enabled templates for the given context type.
306      *
307      * @param contextTypeId the id of the context type of the requested templates, or <code>null</code> if all templates should be returned
308      * @return all enabled templates for the given context type
309      */

310     public Template[] getTemplates(String JavaDoc contextTypeId) {
311         List JavaDoc templates= new ArrayList JavaDoc();
312         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
313             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
314             if (data.isEnabled() && !data.isDeleted() && (contextTypeId == null || contextTypeId.equals(data.getTemplate().getContextTypeId())))
315                 templates.add(data.getTemplate());
316         }
317
318         return (Template[]) templates.toArray(new Template[templates.size()]);
319     }
320
321     /**
322      * Returns the first enabled template that matches the name.
323      *
324      * @param name the name of the template searched for
325      * @return the first enabled template that matches both name and context type id, or <code>null</code> if none is found
326      */

327     public Template findTemplate(String JavaDoc name) {
328         return findTemplate(name, null);
329     }
330
331     /**
332      * Returns the first enabled template that matches both name and context type id.
333      *
334      * @param name the name of the template searched for
335      * @param contextTypeId the context type id to clip unwanted templates, or <code>null</code> if any context type is OK
336      * @return the first enabled template that matches both name and context type id, or <code>null</code> if none is found
337      */

338     public Template findTemplate(String JavaDoc name, String JavaDoc contextTypeId) {
339         Assert.isNotNull(name);
340
341         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
342             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
343             Template template= data.getTemplate();
344             if (data.isEnabled() && !data.isDeleted()
345                     && (contextTypeId == null || contextTypeId.equals(template.getContextTypeId()))
346                     && name.equals(template.getName()))
347                 return template;
348         }
349
350         return null;
351     }
352
353     /**
354      * Returns the first enabled template that matches the given template id.
355      *
356      * @param id the id of the template searched for
357      * @return the first enabled template that matches id, or <code>null</code> if none is found
358      * @since 3.1
359      */

360     public Template findTemplateById(String JavaDoc id) {
361         TemplatePersistenceData data= getTemplateData(id);
362         if (data != null && !data.isDeleted())
363             return data.getTemplate();
364
365         return null;
366     }
367
368     /**
369      * Returns all template data.
370      *
371      * @param includeDeleted whether to include deleted data
372      * @return all template data, whether enabled or not
373      */

374     public TemplatePersistenceData[] getTemplateData(boolean includeDeleted) {
375         List JavaDoc datas= new ArrayList JavaDoc();
376         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
377             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
378             if (includeDeleted || !data.isDeleted())
379                 datas.add(data);
380         }
381
382         return (TemplatePersistenceData[]) datas.toArray(new TemplatePersistenceData[datas.size()]);
383     }
384
385     /**
386      * Returns the template data of the template with id <code>id</code> or
387      * <code>null</code> if no such template can be found.
388      *
389      * @param id the id of the template data
390      * @return the template data of the template with id <code>id</code> or <code>null</code>
391      * @since 3.1
392      */

393     public TemplatePersistenceData getTemplateData(String JavaDoc id) {
394         Assert.isNotNull(id);
395         for (Iterator JavaDoc it= fTemplates.iterator(); it.hasNext();) {
396             TemplatePersistenceData data= (TemplatePersistenceData) it.next();
397             if (id.equals(data.getId()))
398                 return data;
399         }
400
401         return null;
402     }
403
404     private void loadCustomTemplates() throws IOException JavaDoc {
405         String JavaDoc pref= fPreferenceStore.getString(fKey);
406         if (pref != null && pref.trim().length() > 0) {
407             Reader JavaDoc input= new StringReader JavaDoc(pref);
408             TemplateReaderWriter reader= new TemplateReaderWriter();
409             TemplatePersistenceData[] datas= reader.read(input);
410             for (int i= 0; i < datas.length; i++) {
411                 TemplatePersistenceData data= datas[i];
412                 add(data);
413             }
414         }
415     }
416
417     /**
418      * Validates a template against the context type registered in the context
419      * type registry. Returns always <code>true</code> if no registry is
420      * present.
421      *
422      * @param template the template to validate
423      * @return <code>true</code> if validation is successful or no context
424      * type registry is specified, <code>false</code> if validation
425      * fails
426      */

427     private boolean validateTemplate(Template template) {
428         String JavaDoc contextTypeId= template.getContextTypeId();
429         if (contextExists(contextTypeId)) {
430             if (fRegistry != null)
431                 try {
432                     fRegistry.getContextType(contextTypeId).validate(template.getPattern());
433                 } catch (TemplateException e) {
434                     return false;
435                 }
436             return true;
437         }
438
439         return false;
440     }
441
442     /**
443      * Returns <code>true</code> if a context type id specifies a valid context type
444      * or if no context type registry is present.
445      *
446      * @param contextTypeId the context type id to look for
447      * @return <code>true</code> if the context type specified by the id
448      * is present in the context type registry, or if no registry is
449      * specified
450      */

451     private boolean contextExists(String JavaDoc contextTypeId) {
452         return contextTypeId != null && (fRegistry == null || fRegistry.getContextType(contextTypeId) != null);
453     }
454
455     /**
456      * Returns the registry.
457      *
458      * @return Returns the registry
459      */

460     protected final ContextTypeRegistry getRegistry() {
461         return fRegistry;
462     }
463 }
464
465
Popular Tags