001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.wpilibj2.command; 006 007import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.util.sendable.SendableBuilder; 010import java.util.Map; 011import java.util.function.Supplier; 012 013/** 014 * A command composition that runs one of a selection of commands using a selector and a key to 015 * command mapping. 016 * 017 * <p>The rules for command compositions apply: command instances that are passed to it cannot be 018 * added to any other composition or scheduled individually, and the composition requires all 019 * subsystems its components require. 020 * 021 * <p>This class is provided by the NewCommands VendorDep 022 * 023 * @param <K> The type of key used to select the command 024 */ 025public class SelectCommand<K> extends Command { 026 private final Map<K, Command> m_commands; 027 private final Supplier<? extends K> m_selector; 028 private Command m_selectedCommand; 029 private boolean m_runsWhenDisabled = true; 030 private InterruptionBehavior m_interruptBehavior = InterruptionBehavior.kCancelIncoming; 031 032 private final Command m_defaultCommand = 033 new PrintCommand("SelectCommand selector value does not correspond to any command!"); 034 035 /** 036 * Creates a new SelectCommand. 037 * 038 * @param commands the map of commands to choose from 039 * @param selector the selector to determine which command to run 040 */ 041 @SuppressWarnings("this-escape") 042 public SelectCommand(Map<K, Command> commands, Supplier<? extends K> selector) { 043 m_commands = requireNonNullParam(commands, "commands", "SelectCommand"); 044 m_selector = requireNonNullParam(selector, "selector", "SelectCommand"); 045 046 CommandScheduler.getInstance().registerComposedCommands(m_defaultCommand); 047 CommandScheduler.getInstance() 048 .registerComposedCommands(commands.values().toArray(new Command[] {})); 049 050 for (Command command : m_commands.values()) { 051 addRequirements(command.getRequirements()); 052 m_runsWhenDisabled &= command.runsWhenDisabled(); 053 if (command.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) { 054 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 055 } 056 } 057 } 058 059 @Override 060 public void initialize() { 061 m_selectedCommand = m_commands.getOrDefault(m_selector.get(), m_defaultCommand); 062 m_selectedCommand.initialize(); 063 } 064 065 @Override 066 public void execute() { 067 m_selectedCommand.execute(); 068 } 069 070 @Override 071 public void end(boolean interrupted) { 072 m_selectedCommand.end(interrupted); 073 } 074 075 @Override 076 public boolean isFinished() { 077 return m_selectedCommand.isFinished(); 078 } 079 080 @Override 081 public boolean runsWhenDisabled() { 082 return m_runsWhenDisabled; 083 } 084 085 @Override 086 public InterruptionBehavior getInterruptionBehavior() { 087 return m_interruptBehavior; 088 } 089 090 @Override 091 public void initSendable(SendableBuilder builder) { 092 super.initSendable(builder); 093 094 builder.addStringProperty( 095 "selected", () -> m_selectedCommand == null ? "null" : m_selectedCommand.getName(), null); 096 } 097}