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 public SelectCommand(Map<K, Command> commands, Supplier<? extends K> selector) { 042 m_commands = requireNonNullParam(commands, "commands", "SelectCommand"); 043 m_selector = requireNonNullParam(selector, "selector", "SelectCommand"); 044 045 CommandScheduler.getInstance().registerComposedCommands(m_defaultCommand); 046 CommandScheduler.getInstance() 047 .registerComposedCommands(commands.values().toArray(new Command[] {})); 048 049 for (Command command : m_commands.values()) { 050 m_requirements.addAll(command.getRequirements()); 051 m_runsWhenDisabled &= command.runsWhenDisabled(); 052 if (command.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) { 053 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 054 } 055 } 056 } 057 058 @Override 059 public void initialize() { 060 m_selectedCommand = m_commands.getOrDefault(m_selector.get(), m_defaultCommand); 061 m_selectedCommand.initialize(); 062 } 063 064 @Override 065 public void execute() { 066 m_selectedCommand.execute(); 067 } 068 069 @Override 070 public void end(boolean interrupted) { 071 m_selectedCommand.end(interrupted); 072 } 073 074 @Override 075 public boolean isFinished() { 076 return m_selectedCommand.isFinished(); 077 } 078 079 @Override 080 public boolean runsWhenDisabled() { 081 return m_runsWhenDisabled; 082 } 083 084 @Override 085 public InterruptionBehavior getInterruptionBehavior() { 086 return m_interruptBehavior; 087 } 088 089 @Override 090 public void initSendable(SendableBuilder builder) { 091 super.initSendable(builder); 092 093 builder.addStringProperty( 094 "selected", () -> m_selectedCommand == null ? "null" : m_selectedCommand.getName(), null); 095 } 096}