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, either using a selector and a key 015 * to command mapping, or a supplier that returns the command directly at runtime. 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 */ 023public class SelectCommand extends CommandBase { 024 private final Map<Object, Command> m_commands; 025 private final Supplier<Object> m_selector; 026 private Command m_selectedCommand; 027 private boolean m_runsWhenDisabled = true; 028 private InterruptionBehavior m_interruptBehavior = InterruptionBehavior.kCancelIncoming; 029 030 /** 031 * Creates a new SelectCommand. 032 * 033 * @param commands the map of commands to choose from 034 * @param selector the selector to determine which command to run 035 */ 036 public SelectCommand(Map<Object, Command> commands, Supplier<Object> selector) { 037 m_commands = requireNonNullParam(commands, "commands", "SelectCommand"); 038 m_selector = requireNonNullParam(selector, "selector", "SelectCommand"); 039 040 CommandScheduler.getInstance() 041 .registerComposedCommands(commands.values().toArray(new Command[] {})); 042 043 for (Command command : m_commands.values()) { 044 m_requirements.addAll(command.getRequirements()); 045 m_runsWhenDisabled &= command.runsWhenDisabled(); 046 if (command.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) { 047 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 048 } 049 } 050 } 051 052 @Override 053 public void initialize() { 054 if (!m_commands.containsKey(m_selector.get())) { 055 m_selectedCommand = 056 new PrintCommand("SelectCommand selector value does not correspond to any command!"); 057 } else { 058 m_selectedCommand = m_commands.get(m_selector.get()); 059 } 060 m_selectedCommand.initialize(); 061 } 062 063 @Override 064 public void execute() { 065 m_selectedCommand.execute(); 066 } 067 068 @Override 069 public void end(boolean interrupted) { 070 m_selectedCommand.end(interrupted); 071 } 072 073 @Override 074 public boolean isFinished() { 075 return m_selectedCommand.isFinished(); 076 } 077 078 @Override 079 public boolean runsWhenDisabled() { 080 return m_runsWhenDisabled; 081 } 082 083 @Override 084 public InterruptionBehavior getInterruptionBehavior() { 085 return m_interruptBehavior; 086 } 087 088 @Override 089 public void initSendable(SendableBuilder builder) { 090 super.initSendable(builder); 091 092 builder.addStringProperty( 093 "selected", () -> m_selectedCommand == null ? "null" : m_selectedCommand.getName(), null); 094 } 095}