Automatic save of JFrame components to preference node

By nchalon on Jul 23, 2014

For a personal project i needed to have a quick and easy system to save settings from a JFrame to preferences node using jdk preference api.

// Sample class that uses SettingsManager
public class MyForm{
  ...
  SettingsManager settingsManager;
  public MyForm(){
    // this will restore previously saved values + add auto save handlers
    settingsManager = new SettingsManager(this);
  }
  ...
  public void onResetButtonClick(....){
    // this will reset values to original values
    settingsManager.reset()
  }
}
package you.define.it;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import static com.google.common.collect.Iterables.all;
import com.google.common.collect.Lists;
import static com.google.common.collect.Lists.newArrayList;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.prefs.Preferences;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * This piece of code is provided as is. Use at your own risk.
 *
 * @author nchalon
 */
public class SettingsManager {

    private static final Logger LOGGER = LoggerFactory.getLogger(SettingsManager.class);
    private static final String DEFAULT = "_DEFAULT";

    static SettingsManager getSettingsManager(Object object) {
        return new SettingsManager(object);
    }

    private final Object object;
    private Preferences userPreferences;
    private ArrayList<Field> fields;

    public void reset() {
        all(fields, new Predicate<Field>() {
            @Override
            public boolean apply(Field field) {
                resetFieldContent(field);
                return true;
            }
        });
    }

    private SettingsManager(Object object) {
        this.object = object;
        this.fields = newArrayList(object.getClass().getDeclaredFields());
        userPreferences = Preferences.userNodeForPackage(object.getClass());
        try {
            extractFieldsContent();
        } catch (Exception ex) {
            LOGGER.warn("Unable to retreive class data from preferences");
        }
    }

    private void extractFieldsContent() throws Exception {
        all(fields, new Predicate<Field>() {
            @Override
            public boolean apply(Field field) {
                extractFieldContent(field);
                return true;
            }
        });

    }
    private void extractFieldContent(Field field) {
        try {
            field.setAccessible(true);
            final Object theField = field.get(object);
            if (theField != null) {
                if (theField.getClass().isAssignableFrom(JTextField.class)) {
                    handleTextField(field, ((JTextField) theField));
                } else if (theField.getClass().isAssignableFrom(JFormattedTextField.class)) {
                    handleTextField(field, ((JTextField) theField));
                } else if (theField.getClass().isAssignableFrom(JCheckBox.class)) {
                    handleCheckbox(field, ((JCheckBox) theField));
                } else if (theField.getClass().isAssignableFrom(JComboBox.class)) {
                    handleComboBox(field, ((JComboBox) theField));
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
            LOGGER.error("Unable to extract field content",ex);
        }
    }

    private void handleTextField(final Field field, final JTextField textField) {
        userPreferences.put(field.getName() + DEFAULT, textField.getText());
        textField.setText(userPreferences.get(field.getName(), textField.getText()));
        textField.getDocument().addDocumentListener(new DocumentListener() {
            @Override
            public void insertUpdate(DocumentEvent e) {
                handleChange();
            }

            @Override
            public void removeUpdate(DocumentEvent e) {
                handleChange();
            }

            @Override
            public void changedUpdate(DocumentEvent e) {
                handleChange();
            }

            public void handleChange() {
                userPreferences.put(field.getName(), textField.getText());
            }
        });
    }

    private void handleCheckbox(final Field field, final JCheckBox checkBox) {
        userPreferences.putBoolean(field.getName() + DEFAULT, checkBox.isSelected());
        checkBox.setSelected(userPreferences.getBoolean(field.getName(), checkBox.isSelected()));
        checkBox.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
                userPreferences.putBoolean(field.getName(), checkBox.isSelected());
            }
        });
    }

    private void handleComboBox(final Field field, final JComboBox comboBox) {
        userPreferences.putInt(field.getName() + DEFAULT, comboBox.getSelectedIndex());
        comboBox.setSelectedIndex(userPreferences.getInt(field.getName(), comboBox.getSelectedIndex()));
        comboBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                userPreferences.putInt(field.getName(), comboBox.getSelectedIndex());
            }
        });
    }

    private void resetFieldContent(Field field){
        try {
            field.setAccessible(true);
            final Object theField = field.get(object);
            if (theField != null) {
                if (theField.getClass().isAssignableFrom(JTextField.class)) {
                    ((JTextField) theField).setText(userPreferences.get(field.getName() + DEFAULT, ""));
                } else if (theField.getClass().isAssignableFrom(JFormattedTextField.class)) {
                    ((JTextField) theField).setText(userPreferences.get(field.getName() + DEFAULT, ""));
                } else if (theField.getClass().isAssignableFrom(JCheckBox.class)) {
                    ((JCheckBox) theField).setSelected(userPreferences.getBoolean(field.getName() + DEFAULT, false));
                } else if (theField.getClass().isAssignableFrom(JComboBox.class)) {
                    ((JComboBox) theField).setSelectedIndex(userPreferences.getInt(field.getName() + DEFAULT, 0));
                }
                userPreferences.remove(field.getName());
            }
        } catch (IllegalAccessException | IllegalArgumentException | SecurityException ex) {
            LOGGER.error("Unable to reset field content",ex);
        }
    }
}

Comments

Sign in to comment.
dcease   -  Jul 24, 2014

Lmfao, java looks so complicated. And even when you call it easy...

 Respond  
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.