blob: 2c3ab23c29aa1d73b4d5fe02a25d2ec453e70b5a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2018 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.jface.text.templates.persistence;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import org.eclipse.core.runtime.Assert;
import org.eclipse.text.templates.ContextTypeRegistry;
import org.eclipse.text.templates.TemplatePersistenceData;
import org.eclipse.text.templates.TemplateReaderWriter;
import org.eclipse.text.templates.TemplateStoreCore;
import org.eclipse.jface.preference.IPersistentPreferenceStore;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
/**
* A collection of templates. Clients may instantiate this class. In order to
* load templates contributed using the <code>org.eclipse.ui.editors.templates</code>
* extension point, use a <code>ContributionTemplateStore</code>.
*
* @since 3.0
*/
public class TemplateStore extends TemplateStoreCore {
/** The preference store. */
private IPreferenceStore fPreferenceStore;
/**
* The property listener, if any is registered, <code>null</code> otherwise.
*
* @since 3.2
*/
private IPropertyChangeListener fPropertyListener;
/**
* Set to <code>true</code> if property change events should be ignored (e.g. during writing
* to the preference store).
*
* @since 3.2
*/
private boolean fIgnorePreferenceStoreChanges= false;
/**
* Creates a new template store.
*
* @param store the preference store in which to store custom templates
* under <code>key</code>
* @param key the key into <code>store</code> where to store custom
* templates
*/
public TemplateStore(IPreferenceStore store, String key) {
super(null, key);
Assert.isNotNull(store);
Assert.isNotNull(key);
fPreferenceStore= store;
}
/**
* Creates a new template store with a context type registry. Only templates
* that specify a context type contained in the registry will be loaded by
* this store if the registry is not <code>null</code>.
*
* @param registry a context type registry, or <code>null</code> if all
* templates should be loaded
* @param store the preference store in which to store custom templates
* under <code>key</code>
* @param key the key into <code>store</code> where to store custom
* templates
*/
public TemplateStore(org.eclipse.jface.text.templates.ContextTypeRegistry registry, IPreferenceStore store, String key) {
super(registry, null, key);
fPreferenceStore= store;
}
/**
* Loads the templates from contributions and preferences.
*
* @throws IOException if loading fails.
*/
@Override
public void load() throws IOException {
internalGetTemplates().clear();
loadContributedTemplates();
loadCustomTemplates();
}
/**
* Starts listening for property changes on the preference store. If the configured preference
* key changes, the template store is {@link #load() reloaded}. Call
* {@link #stopListeningForPreferenceChanges()} to remove any listener and stop the
* auto-updating behavior.
*
* @since 3.2
*/
@Override
public final void startListeningForPreferenceChanges() {
if (fPropertyListener == null) {
fPropertyListener= new IPropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
/*
* Don't load if we are in the process of saving ourselves. We are in sync anyway after the
* save operation, and clients may trigger reloading by listening to preference store
* updates.
*/
if (!fIgnorePreferenceStoreChanges && getKey().equals(event.getProperty()))
try {
load();
} catch (IOException x) {
handleException(x);
}
}
};
fPreferenceStore.addPropertyChangeListener(fPropertyListener);
}
}
/**
* Stops the auto-updating behavior started by calling
* {@link #startListeningForPreferenceChanges()}.
*
* @since 3.2
*/
@Override
public final void stopListeningForPreferenceChanges() {
if (fPropertyListener != null) {
fPreferenceStore.removePropertyChangeListener(fPropertyListener);
fPropertyListener= null;
}
}
/**
* Saves the templates to the preferences.
*
* @throws IOException if the templates cannot be written
*/
@Override
public void save() throws IOException {
ArrayList<TemplatePersistenceData> custom= new ArrayList<>();
for (TemplatePersistenceData data : internalGetTemplates()) {
if (data.isCustom() && !(data.isUserAdded() && data.isDeleted())) // don't save deleted user-added templates
custom.add(data);
}
StringWriter output= new StringWriter();
TemplateReaderWriter writer= new TemplateReaderWriter();
writer.save(custom.toArray(new TemplatePersistenceData[custom.size()]), output);
fIgnorePreferenceStoreChanges= true;
try {
fPreferenceStore.setValue(getKey(), output.toString());
if (fPreferenceStore instanceof IPersistentPreferenceStore)
((IPersistentPreferenceStore)fPreferenceStore).save();
} finally {
fIgnorePreferenceStoreChanges= false;
}
}
/**
* Deletes all user-added templates and reverts all contributed templates.
*
* @param doSave <code>true</code> if the store should be saved after restoring
* @since 3.5
*/
@Override
public void restoreDefaults(boolean doSave) {
String oldValue= null;
if (!doSave)
oldValue= fPreferenceStore.getString(getKey());
try {
fIgnorePreferenceStoreChanges= true;
fPreferenceStore.setToDefault(getKey());
} finally {
fIgnorePreferenceStoreChanges= false;
}
try {
load();
} catch (IOException x) {
// can't log from jface-text
handleException(x);
}
if (oldValue != null) {
try {
fIgnorePreferenceStoreChanges= true;
fPreferenceStore.putValue(getKey(), oldValue);
} finally {
fIgnorePreferenceStoreChanges= false;
}
}
}
private void loadCustomTemplates() throws IOException {
String pref= fPreferenceStore.getString(getKey());
if (pref != null && pref.trim().length() > 0) {
Reader input= new StringReader(pref);
TemplateReaderWriter reader= new TemplateReaderWriter();
TemplatePersistenceData[] datas= reader.read(input);
for (TemplatePersistenceData data : datas) {
add(data);
}
}
}
@Override
protected final org.eclipse.jface.text.templates.ContextTypeRegistry getRegistry() {
ContextTypeRegistry registry= super.getRegistry();
org.eclipse.jface.text.templates.ContextTypeRegistry res= new org.eclipse.jface.text.templates.ContextTypeRegistry();
registry.contextTypes().forEachRemaining(t -> res.addContextType(t));
return res;
}
public void add(org.eclipse.jface.text.templates.persistence.TemplatePersistenceData data) {
super.add(data);
}
public void delete(org.eclipse.jface.text.templates.persistence.TemplatePersistenceData data) {
super.delete(data);
}
@Override
public org.eclipse.jface.text.templates.persistence.TemplatePersistenceData[] getTemplateData(boolean includeDeleted) {
TemplatePersistenceData[] list= super.getTemplateData(includeDeleted);
org.eclipse.jface.text.templates.persistence.TemplatePersistenceData[] wraps= new org.eclipse.jface.text.templates.persistence.TemplatePersistenceData[list.length];
for (int i= 0; i < wraps.length; i++) {
wraps[i]= new org.eclipse.jface.text.templates.persistence.TemplatePersistenceData(list[i]);
}
return wraps;
}
@Override
public org.eclipse.jface.text.templates.persistence.TemplatePersistenceData getTemplateData(String id) {
TemplatePersistenceData data= super.getTemplateData(id);
org.eclipse.jface.text.templates.persistence.TemplatePersistenceData wrap= new org.eclipse.jface.text.templates.persistence.TemplatePersistenceData(data);
return wrap;
}
protected void internalAdd(org.eclipse.jface.text.templates.persistence.TemplatePersistenceData data) {
super.internalAdd(data);
}
}