package usr.erichschroeter.jpreferences;
import java.util.prefs.BackingStoreException;
import java.util.prefs.PreferenceChangeEvent;
import java.util.prefs.PreferenceChangeListener;
import java.util.prefs.Preferences;
import javax.swing.table.AbstractTableModel;
/**
* The <code>PreferenceTableModel</code> wraps a {@link Preferences} object to
* view and edit its children preferences.
*
* @author Erich Schroeter, http://www.roseindia.net/javatutorials/javaapi.shtml
*/
@SuppressWarnings("serial")
public class PreferenceTableModel extends AbstractTableModel {
/** The column index for the keys. */
private static final int KEY_COLUMN = 0;
/** The column index for the values. */
private static final int VALUE_COLUMN = 1;
/** The preference object to wrap. */
private Preferences pref;
/** A reference to the preference keys. */
private String[] keys;
/** Whether to allow preferences to be deleted. */
private boolean deleteAllowed;
/** Whether to allow preferences to be added. */
private boolean addAllowed;
/** Whether to allow preference keys to be modified. */
private boolean editKeysAllowed;
/** Whether to allow preference values to be modified. */
private boolean editValuesAllowed;
/**
* Constructs a <code>PreferenceTableModel</code> wrapping the specified
* <code>pref</code>.
*
* @param pref
* the preference object to wrap
*/
public PreferenceTableModel(Preferences pref) {
this.pref = pref;
updateKeys();
pref.addPreferenceChangeListener(new PreferenceChangeListener() {
@Override
public void preferenceChange(PreferenceChangeEvent evt) {
String value = evt.getNewValue();
if (value != null) {
addPreference(evt.getKey(), evt.getNewValue());
} else {
removePreference(evt.getKey());
}
}
});
initializeDefaults();
}
/**
* Initializes the default features to be enabled or disabled.
* <p>
* In derived classes this may be overridden to customize which features are
* enabled or disabled.
*/
protected void initializeDefaults() {
setAddAllowed(true);
setDeleteAllowed(false);
setEditKeysAllowed(false);
setEditValuesAllowed(true);
}
/**
* Resets the reference of {@link #keys} to {@link #pref}
* <code>.keys()</code> and handles catching the
* {@link BackingStoreException} it throws.
*
* @see #sync()
*/
protected void updateKeys() {
try {
keys = pref.keys();
} catch (BackingStoreException e) {
System.out.println("Could not get keys for Preference node: "
+ pref.name());
e.printStackTrace();
keys = new String[0];
}
}
/**
* Calls {@link #pref}<code>.sync()</code> and handles catching the
* {@link BackingStoreException} it throws.
*
* @see #updateKeys()
*/
protected void sync() {
try {
// make sure the backing store is synchronized with latest update
pref.sync();
} catch (BackingStoreException e) {
System.out
.println("Error synchronizing backStore with updated value");
e.printStackTrace();
}
}
/**
* Adds a preference to the preferences node. This method fires a inserted
* <code>TableModelEvent</code> when successfully added.
* <p>
* If <code>key</code> has an existing value associated with it, or if
* <code>key</code> or <code>value</code> is <code>null</code> this method
* changes nothing.
*
* @param key
* the preference key
* @param value
* the preference value
*/
public void addPreference(String key, Object value) {
if (key == null || value == null) {
return; // return immediately
}
String val = pref.get(key, null);
// only add the preference if the key has no associated value
if (val == null) {
pref.put(key, value.toString());
sync();
updateKeys();
fireTableRowsInserted(getRowCount(), getRowCount());
}
}
/**
* Removes the preference associated by <code>key</code>. This method fires
* a deleted <code>TableModelEvent</code> when successfully removed.
* <p>
* If <code>key</code> is <code>null</code> this method changes nothing.
* <p>
* If possible, try to use {@link #removeRow(int)} for better performance.
* This method calls that method after iterating over the keys to find the
* index.
*
* @see #removeRow(int)
* @param key
* the preference to remove
*/
public void removePreference(String key) {
if (key == null) {
return; // return immediately
}
int index = -1;
for (int i = 0; i < keys.length; i++) {
if (keys[i].equals(key)) {
index = i;
// break out of this loop to increase performance
// otherwise we will iterate n every time
break;
}
}
removeRow(index);
}
/**
* Removes the preference at the specified index.This method fires a deleted
* <code>TableModelEvent</code> when successfully removed.
* <p>
* If <code>rowIndex</code> < 0 or <code>rowIndex</code> >=
* <code>{@link #keys}.length</code> this method changes nothing.
*
* @see #removePreference(String)
* @see #sync()
* @see #updateKeys()
* @param rowIndex
* the preference key index (between 0 and number of keys}
*/
public void removeRow(int rowIndex) {
if (rowIndex <= 0 && rowIndex < keys.length) {
pref.remove(keys[rowIndex]);
sync();
updateKeys();
fireTableRowsDeleted(rowIndex, rowIndex);
}
}
/**
* Returns whether to allow preferences to be deleted.
*
* @return <code>true</code> if allowed, else <code>false</code>
*/
public boolean isDeleteAllowed() {
return deleteAllowed;
}
/**
* Enables or disables the ability to delete preferences.
*
* @param enable
* <code>true</code> to allow, <code>false</code> to disallow
* @return the instance for additional configuration
*/
public PreferenceTableModel setDeleteAllowed(boolean enable) {
this.deleteAllowed = enable;
return this;
}
/**
* Returns whether to allow preferences to be added.
*
* @return <code>true</code> if allowed, else <code>false</code>
*/
public boolean isAddAllowed() {
return addAllowed;
}
/**
* Enables or disables the ability to add preferences.
*
* @param enable
* <code>true</code> to allow, <code>false</code> to disallow
* @return the instance for additional configuration
*/
public PreferenceTableModel setAddAllowed(boolean enable) {
this.addAllowed = enable;
return this;
}
/**
* Returns whether to allow preference values to be modified.
*
* @return <code>true</code> if allowed, else <code>false</code>
*/
public boolean isEditValuesAllowed() {
return editValuesAllowed;
}
/**
* Enables or disables the ability to modify preference values.
*
* @param enable
* <code>true</code> to allow, <code>false</code> to disallow
* @return the instance for additional configuration
*/
public PreferenceTableModel setEditValuesAllowed(boolean enable) {
this.editValuesAllowed = enable;
return this;
}
/**
* Returns whether to allow preference keys to be modified.
*
* @return <code>true</code> if allowed, else <code>false</code>
*/
public boolean isEditKeysAllowed() {
return editKeysAllowed;
}
/**
* Enables or disables the ability to modify preference keys.
*
* @param enable
* <code>true</code> to allow, <code>false</code> to disallow
* @return the instance for additional configuration
*/
public PreferenceTableModel setEditKeysAllowed(boolean enable) {
this.editKeysAllowed = enable;
return this;
}
@Override
public String getColumnName(int column) {
String name = null;
switch (column) {
case KEY_COLUMN:
name = "Key";
break;
case VALUE_COLUMN:
name = "Value";
break;
default:
name = "-";
}
return name;
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
boolean editable = false;
switch (columnIndex) {
case KEY_COLUMN:
editable = isEditKeysAllowed();
break;
case VALUE_COLUMN:
editable = isEditValuesAllowed();
break;
default:
editable = false;
}
return editable;
}
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
pref.put(keys[rowIndex], aValue.toString());
sync();
fireTableCellUpdated(rowIndex, columnIndex);
}
@Override
public Object getValueAt(int row, int column) {
Object value = null;
String key = keys[row];
if (column == KEY_COLUMN) {
value = key;
} else {
value = pref.get(key, "(Unknown)");
}
return value;
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public int getRowCount() {
return keys.length;
}
}