001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. 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.smartdashboard;
009
010import java.util.LinkedHashMap;
011
012import edu.wpi.first.networktables.NetworkTableEntry;
013import edu.wpi.first.wpilibj.Sendable;
014import edu.wpi.first.wpilibj.SendableBase;
015import edu.wpi.first.wpilibj.command.Command;
016
017import static java.util.Objects.requireNonNull;
018
019/**
020 * The {@link SendableChooser} class is a useful tool for presenting a selection of options to the
021 * {@link SmartDashboard}.
022 *
023 * <p>For instance, you may wish to be able to select between multiple autonomous modes. You can do
024 * this by putting every possible {@link Command} you want to run as an autonomous into a {@link
025 * SendableChooser} and then put it into the {@link SmartDashboard} to have a list of options appear
026 * on the laptop. Once autonomous starts, simply ask the {@link SendableChooser} what the selected
027 * value is.
028 *
029 * @param <V> The type of the values to be stored
030 */
031public class SendableChooser<V> extends SendableBase implements Sendable {
032  /**
033   * The key for the default value.
034   */
035  private static final String DEFAULT = "default";
036  /**
037   * The key for the selected option.
038   */
039  private static final String SELECTED = "selected";
040  /**
041   * The key for the option array.
042   */
043  private static final String OPTIONS = "options";
044  /**
045   * A map linking strings to the objects the represent.
046   */
047  private final LinkedHashMap<String, V> m_map = new LinkedHashMap<>();
048  private String m_defaultChoice = "";
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 {@link SmartDashboard} on the desktop, the
058   * object will appear as the given name.
059   *
060   * @param name   the name of the option
061   * @param object the option
062   */
063  public void addObject(String name, V object) {
064    m_map.put(name, object);
065  }
066
067  /**
068   * Add the given object to the list of options and marks it as the default. Functionally, this is
069   * very close to {@link #addObject(String, Object)} except that it will use this as the default
070   * option if none other is explicitly selected.
071   *
072   * @param name   the name of the option
073   * @param object the option
074   */
075  public void addDefault(String name, V object) {
076    requireNonNull(name, "Provided name was null");
077
078    m_defaultChoice = name;
079    addObject(name, object);
080  }
081
082  /**
083   * Returns the selected option. If there is none selected, it will return the default. If there is
084   * none selected and no default, then it will return {@code null}.
085   *
086   * @return the option selected
087   */
088  public V getSelected() {
089    String selected = m_defaultChoice;
090    if (m_tableSelected != null) {
091      selected = m_tableSelected.getString(m_defaultChoice);
092    }
093    return m_map.get(selected);
094  }
095
096  private NetworkTableEntry m_tableSelected;
097
098  @Override
099  public void initSendable(SendableBuilder builder) {
100    builder.setSmartDashboardType("String Chooser");
101    builder.addStringProperty(DEFAULT, () -> {
102      return m_defaultChoice;
103    }, null);
104    builder.addStringArrayProperty(OPTIONS, () -> {
105      return m_map.keySet().toArray(new String[0]);
106    }, null);
107    m_tableSelected = builder.getEntry(SELECTED);
108  }
109}