001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import java.util.Vector;
011
012import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
013import edu.wpi.first.wpilibj.hal.HAL;
014import edu.wpi.first.wpilibj.networktables.NetworkTable;
015import edu.wpi.first.wpilibj.tables.ITable;
016import edu.wpi.first.wpilibj.tables.ITableListener;
017import edu.wpi.first.wpilibj.tables.TableKeyNotDefinedException;
018
019/**
020 * The preferences class provides a relatively simple way to save important values to the roboRIO to
021 * access the next time the roboRIO is booted.
022 *
023 * <p> This class loads and saves from a file inside the roboRIO. The user can not access the file
024 * directly, but may modify values at specific fields which will then be automatically saved to the
025 * file by the NetworkTables server. </p>
026 *
027 * <p> This class is thread safe. </p>
028 *
029 * <p> This will also interact with {@link NetworkTable} by creating a table called "Preferences"
030 * with all the key-value pairs. </p>
031 */
032public class Preferences {
033
034  /**
035   * The Preferences table name.
036   */
037  private static final String TABLE_NAME = "Preferences";
038  /**
039   * The singleton instance.
040   */
041  private static Preferences instance;
042  /**
043   * The network table.
044   */
045  private final NetworkTable m_table;
046  /**
047   * Listener to set all Preferences values to persistent (for backwards compatibility with old
048   * dashboards).
049   */
050  private final ITableListener m_listener = new ITableListener() {
051    @Override
052    public void valueChanged(ITable table, String key, Object value, boolean isNew) {
053      // unused
054    }
055
056    @Override
057    public void valueChangedEx(ITable table, String key, Object value, int flags) {
058      table.setPersistent(key);
059    }
060  };
061
062  /**
063   * Returns the preferences instance.
064   *
065   * @return the preferences instance
066   */
067  public static synchronized Preferences getInstance() {
068    if (instance == null) {
069      instance = new Preferences();
070    }
071    return instance;
072  }
073
074  /**
075   * Creates a preference class.
076   */
077  private Preferences() {
078    m_table = NetworkTable.getTable(TABLE_NAME);
079    m_table.addTableListenerEx(m_listener, ITable.NOTIFY_NEW | ITable.NOTIFY_IMMEDIATE);
080    HAL.report(tResourceType.kResourceType_Preferences, 0);
081  }
082
083  /**
084   * Gets the vector of keys.
085   * @return a vector of the keys
086   */
087  public Vector getKeys() {
088    Vector<String> keys = new Vector<String>();
089    for (String key : m_table.getKeys()) {
090      keys.add(key);
091    }
092    return keys;
093  }
094
095  /**
096   * Puts the given string into the preferences table.
097   *
098   * @param key   the key
099   * @param value the value
100   * @throws NullPointerException if value is null
101   */
102  public void putString(String key, String value) {
103    if (value == null) {
104      throw new NullPointerException("Value is null");
105    }
106    m_table.putString(key, value);
107    m_table.setPersistent(key);
108  }
109
110  /**
111   * Puts the given int into the preferences table.
112   *
113   * @param key   the key
114   * @param value the value
115   */
116  public void putInt(String key, int value) {
117    m_table.putNumber(key, value);
118    m_table.setPersistent(key);
119  }
120
121  /**
122   * Puts the given double into the preferences table.
123   *
124   * @param key   the key
125   * @param value the value
126   */
127  public void putDouble(String key, double value) {
128    m_table.putNumber(key, value);
129    m_table.setPersistent(key);
130  }
131
132  /**
133   * Puts the given float into the preferences table.
134   *
135   * @param key   the key
136   * @param value the value
137   */
138  public void putFloat(String key, float value) {
139    m_table.putNumber(key, value);
140    m_table.setPersistent(key);
141  }
142
143  /**
144   * Puts the given boolean into the preferences table.
145   *
146   * @param key   the key
147   * @param value the value
148   */
149  public void putBoolean(String key, boolean value) {
150    m_table.putBoolean(key, value);
151    m_table.setPersistent(key);
152  }
153
154  /**
155   * Puts the given long into the preferences table.
156   *
157   * @param key   the key
158   * @param value the value
159   */
160  public void putLong(String key, long value) {
161    m_table.putNumber(key, value);
162    m_table.setPersistent(key);
163  }
164
165  /**
166   * Returns whether or not there is a key with the given name.
167   *
168   * @param key the key
169   * @return if there is a value at the given key
170   */
171  public boolean containsKey(String key) {
172    return m_table.containsKey(key);
173  }
174
175  /**
176   * Remove a preference.
177   *
178   * @param key the key
179   */
180  public void remove(String key) {
181    m_table.delete(key);
182  }
183
184  /**
185   * Returns the string at the given key. If this table does not have a value for that position,
186   * then the given backup value will be returned.
187   *
188   * @param key    the key
189   * @param backup the value to return if none exists in the table
190   * @return either the value in the table, or the backup
191   */
192  public String getString(String key, String backup) {
193    return m_table.getString(key, backup);
194  }
195
196  /**
197   * Returns the int at the given key. If this table does not have a value for that position, then
198   * the given backup value will be returned.
199   *
200   * @param key    the key
201   * @param backup the value to return if none exists in the table
202   * @return either the value in the table, or the backup
203   */
204  public int getInt(String key, int backup) {
205    try {
206      return (int) m_table.getNumber(key);
207    } catch (TableKeyNotDefinedException ex) {
208      return backup;
209    }
210  }
211
212  /**
213   * Returns the double at the given key. If this table does not have a value for that position,
214   * then the given backup value will be returned.
215   *
216   * @param key    the key
217   * @param backup the value to return if none exists in the table
218   * @return either the value in the table, or the backup
219   */
220  public double getDouble(String key, double backup) {
221    return m_table.getDouble(key, backup);
222  }
223
224  /**
225   * Returns the boolean at the given key. If this table does not have a value for that position,
226   * then the given backup value will be returned.
227   *
228   * @param key    the key
229   * @param backup the value to return if none exists in the table
230   * @return either the value in the table, or the backup
231   */
232  public boolean getBoolean(String key, boolean backup) {
233    return m_table.getBoolean(key, backup);
234  }
235
236  /**
237   * Returns the float at the given key. If this table does not have a value for that position, then
238   * the given backup value will be returned.
239   *
240   * @param key    the key
241   * @param backup the value to return if none exists in the table
242   * @return either the value in the table, or the backup
243   */
244  public float getFloat(String key, float backup) {
245    try {
246      return (float) m_table.getNumber(key);
247    } catch (TableKeyNotDefinedException ex) {
248      return backup;
249    }
250  }
251
252  /**
253   * Returns the long at the given key. If this table does not have a value for that position, then
254   * the given backup value will be returned.
255   *
256   * @param key    the key
257   * @param backup the value to return if none exists in the table
258   * @return either the value in the table, or the backup
259   */
260  public long getLong(String key, long backup) {
261    try {
262      return (long) m_table.getNumber(key);
263    } catch (TableKeyNotDefinedException ex) {
264      return backup;
265    }
266  }
267
268  /**
269   * This function is no longer required, as NetworkTables automatically saves persistent values
270   * (which all Preferences values are) periodically when running as a server.
271   *
272   * @deprecated backwards compatibility shim
273   */
274  @Deprecated
275  public void save() {
276  }
277}