All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.fife.ui.app.Prefs Maven / Gradle / Ivy

/*
 * 02/13/2010
 *
 * Prefs.java - Base class for a simple preferences implementation.
 * Copyright (C) 2010 Robert Futrell
 * http://fifesoft.com/rtext
 * Licensed under a modified BSD license.
 * See the included license file for details.
 */
package org.fife.ui.app;

import java.awt.Color;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Properties;
import javax.swing.KeyStroke;



/**
 * A simple wrapper for preferences for some object.  This class can be used
 * as a simpler replacement for the Java Preferences API for the following
 * reasons:
 * 
 * 
    *
  1. No need to call putXXX() methods for each individual * preference when saving preferences and getXXX() methods * while loading them; all public fields are loaded and stored * appropriately automatically.
  2. *
  3. Uses a simple properties file on all platforms. The standard * Preferences API inconveniently hides its data in the registry on * Windows.
  4. *
  5. As opposed to using java.util.Properties directly, * using this class keeps you from having to convert each type of * preference to and from String. java.awt.Color, for * example, is handled automatically.
  6. *
* * Subclasses should declare all fields as public. All public instance fields * will be saved and loaded in properties file format automatically. While * public fields are usually considered bad OO design, since this class is * solely used for preferences and should usually only be read and used (once) * by a single class, this really isn't such a big deal.

* * Common usage should be as follows: say a class Foo needs to * store preferences between runs of the application. A class could be created * for its preferences, say FooPrefs, that extends * Prefs. The Foo instance could then loads its * preferences like so: * *

 * public void loadPreferences() throws IOException {
 *    FooPrefs prefs = new FooPrefs(); // Initializes to defaults
 *    prefs.load(new File((String)System.getProperty("user.home"), ".foo.prefs"));
 *    this.count = prefs.count;
 *    this.id = prefs.id;
 *    this.background = prefs.bgColor;
 * }
 * 
* * and save its preferences similarly: * *
 * public void savePreferences() throws IOException {
 *    FooPrefs prefs = new FooPrefs();
 *    prefs.count = this.count;
 *    prefs.id = this.id;
 *    prefs.bgColor = this.background;
 *    prefs.save(new File((String)System.getProperty("user.home"), ".foo.prefs"));
 * }
 * 
* * Alternatively (and perhaps more simply), the Foo instance could * instantiate and keep the FooPrefs as a private member. Its * getters and setters that modify its preferences could manipulate the * FooPrefs's values directly. Then at shutdown time, the * Foo instance would simply have to call * prefs.save(File) to save any changes.

* * Modification of the generated properties files by hand is discouraged unless * you are familiar with the details of that specific concrete * Prefs implementation.

* * This class currently handles fields of type: *

    *
  • All primitives (int, double, float, boolean, etc.) *
  • String *
  • String[] *
  • File *
  • Color *
  • KeyStroke *
* * @author Robert Futrell * @version 1.0 */ public abstract class Prefs { /** * Constructor. Sets the value of all preferences to their defaults by * calling {@link #setDefaults()}. */ public Prefs() { setDefaults(); } /** * Returns a string representation of a color in the format * "$aarrggbb". * * @param c The color. If this is null, then a string * representing black is returned. * @return The string. */ private String getColorString(Color c) { String str; if (c==null) { str = "$ff000000"; } else { // Shove argb value into a long, using it directly (or even just // casting it to long) make it interpreted as -1. long argb = c.getRGB() & 0xffffffffL; str = "$" + Long.toHexString(argb+0x100000000L).substring(1); } return str; } private boolean isPrimitiveNumberType(Class type) { return int.class==type || long.class==type || short.class==type || byte.class==type || float.class==type || double.class==type; } /** * Returns whether a field has the proper modifiers to be saved. * * @param field The field. * @return Whether the field should be saved. */ private boolean isSavable(Field field) { int mods = field.getModifiers(); return (mods&Modifier.PUBLIC)==Modifier.PUBLIC && (mods&(Modifier.TRANSIENT|Modifier.FINAL))==0; } /** * Loads this preferences class from a file. * * @param file The file. * @throws IOException If an IO error occurs. * @see #load(InputStream) */ public void load(File file) throws IOException { BufferedInputStream in = new BufferedInputStream( new FileInputStream(file)); try { load(in); } finally { in.close(); } } /** * Loads this preferences class from an input stream. * * @param in The input stream. It is the caller's responsibility to close * this stream. * @throws IOException If an IO error occurs. * @see #load(File) */ public void load(InputStream in) throws IOException { Properties props = new Properties(); props.load(in); Class clazz = getClass(); Field[] fields = clazz.getFields(); for (int i=0; i0) { obj = new Character(value.charAt(0)); } } else if (String.class==type) { obj = value; } else if (String[].class==type) { String[] temp = null; int length = Integer.parseInt(value); if (length>-1) { // -1 => null array temp = new String[length]; for (int j=0; j " + rgba); obj = new Color(rgba, true); } } else if (File.class==type){ // Empty value => still use default if (value.length()>0) { obj = new File((String)value); } } else if (KeyStroke.class==type) { if (value.length()>0) { // returns null if formatted incorrectly obj = KeyStroke.getKeyStroke((String)value); } } else { throw new IOException("Unhandled field type for " + "field: " + name + " (" + type + ")"); } // Only replace the default if a value was found if (obj!=null) { fields[i].set(this, obj); } } } catch (IllegalAccessException iae) { // Never happens throw new IOException(iae.getMessage()); } } } /** * Saves these preferences to a file. * * @param file The file to save to. * @throws IOException If an IO error occurs. * @see #save(OutputStream) */ public void save(File file) throws IOException { BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(file)); try { save(out); } finally { out.close(); } } /** * Saves these preferences to an output stream. The stream will still be * open after this call is made. * * @param out The stream to write to. * @throws IOException If an IO error occurs. * @see #save(File) */ public void save(OutputStream out) throws IOException { Class clazz = getClass(); Field[] fields = clazz.getFields(); Properties props = new Properties(); for (int i=0; i String at that index // was null (can't put null values into Properties) if (array[j]!=null) { props.setProperty(name + "." + j, array[j]); } } } } else if (Color.class==type) { Color c = (Color)value; strVal = getColorString(c); } else if (File.class==type) { if (value!=null) { File file = (File)value; strVal = file.getAbsolutePath(); } } else if (KeyStroke.class==type) { if (value!=null) { KeyStroke ks = (KeyStroke)value; strVal = ks.toString(); } } else { throw new IOException("Unhandled field type for field: " + name + " (" + type + ")"); } // If null value/error parsing number occurred (Properties // won't take null values) if (strVal==null) { strVal = ""; } props.setProperty(name, strVal); } catch (IllegalAccessException iae) { // Never happens iae.printStackTrace(); throw new IOException(iae.getMessage()); } } String header = "Preferences for the " + clazz.getName() + " class"; props.store(out, header); } /** * Sets all fields in this class to their default values. */ public abstract void setDefaults(); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy