001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. 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/*----------------------------------------------------------------------------*/
007package edu.wpi.first.wpilibj.smartdashboard;
008
009import edu.wpi.first.wpilibj.Sendable;
010import edu.wpi.first.wpilibj.command.Command;
011import edu.wpi.first.wpilibj.networktables2.type.StringArray;
012import edu.wpi.first.wpilibj.networktables2.util.List;
013import edu.wpi.first.wpilibj.tables.ITable;
014
015/**
016 * The {@link SendableChooser} class is a useful tool for presenting a selection
017 * of options to the {@link SmartDashboard}.
018 *
019 * <p>For instance, you may wish to be able to select between multiple
020 * autonomous modes. You can do this by putting every possible {@link Command}
021 * you want to run as an autonomous into a {@link SendableChooser} and then put
022 * it into the {@link SmartDashboard} to have a list of options appear on the
023 * laptop. Once autonomous starts, simply ask the {@link SendableChooser} what
024 * the selected value is.</p>
025 *
026 * @author Joe Grinstead
027 */
028public class SendableChooser implements Sendable {
029
030    /**
031     * The key for the default value
032     */
033    private static final String DEFAULT = "default";
034    /**
035     * The key for the selected option
036     */
037    private static final String SELECTED = "selected";
038    /**
039     * The key for the option array
040     */
041    private static final String OPTIONS = "options";
042    /**
043     * A table linking strings to the objects the represent
044     */
045    private StringArray choices = new StringArray();
046    private List values = new List();
047    private String defaultChoice = null;
048    private Object defaultValue = null;
049
050    /**
051     * Instantiates a {@link SendableChooser}.
052     */
053    public SendableChooser() {
054    }
055
056    /**
057     * Adds the given object to the list of options. On the
058     * {@link SmartDashboard} on the desktop, the object will appear as the
059     * given name.
060     *
061     * @param name the name of the option
062     * @param object the option
063     */
064    public void addObject(String name, Object object) {
065        //if we don't have a default, set the default automatically
066        if (defaultChoice == null) {
067            addDefault(name, object);
068            return;
069        }
070        for (int i = 0; i < choices.size(); ++i) {
071            if (choices.get(i).equals(name)) {
072                choices.set(i, name);
073                values.set(i, object);
074                return;
075            }
076        }
077        //not found
078        choices.add(name);
079        values.add(object);
080        if (table != null) {
081            table.putValue(OPTIONS, choices);
082        }
083    }
084
085    /**
086     * Add the given object to the list of options and marks it as the default.
087     * Functionally, this is very close to
088     * {@link SendableChooser#addObject(java.lang.String, java.lang.Object) addObject(...)}
089     * except that it will use this as the default option if none other is
090     * explicitly selected.
091     *
092     * @param name the name of the option
093     * @param object the option
094     */
095    public void addDefault(String name, Object object) {
096        if (name == null) {
097            throw new NullPointerException("Name cannot be null");
098        }
099        defaultChoice = name;
100        defaultValue = object;
101        if (table != null) {
102            table.putString(DEFAULT, defaultChoice);
103        }
104        addObject(name, object);
105    }
106
107    /**
108     * Returns the selected option. If there is none selected, it will return
109     * the default. If there is none selected and no default, then it will
110     * return {@code null}.
111     *
112     * @return the option selected
113     */
114    public Object getSelected() {
115        String selected = table.getString(SELECTED, null);
116        for (int i = 0; i < values.size(); ++i) {
117            if (choices.get(i).equals(selected)) {
118                return values.get(i);
119            }
120        }
121        return defaultValue;
122
123    }
124
125    public String getSmartDashboardType() {
126        return "String Chooser";
127    }
128    private ITable table;
129
130    public void initTable(ITable table) {
131        this.table = table;
132        if (table != null) {
133            table.putValue(OPTIONS, choices);
134            if (defaultChoice != null) {
135                table.putString(DEFAULT, defaultChoice);
136            }
137        }
138    }
139
140    /**
141     * {@inheritDoc}
142     */
143    public ITable getTable() {
144        return table;
145    }
146}