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 final Supplier<Command> m_toRun; 027 private Command m_selectedCommand; 028 private boolean m_runsWhenDisabled = true; 029 private InterruptionBehavior m_interruptBehavior = InterruptionBehavior.kCancelIncoming; 030 031 /** 032 * Creates a new SelectCommand. 033 * 034 * @param commands the map of commands to choose from 035 * @param selector the selector to determine which command to run 036 */ 037 public SelectCommand(Map<Object, Command> commands, Supplier<Object> selector) { 038 m_commands = requireNonNullParam(commands, "commands", "SelectCommand"); 039 m_selector = requireNonNullParam(selector, "selector", "SelectCommand"); 040 041 CommandScheduler.getInstance() 042 .registerComposedCommands(commands.values().toArray(new Command[] {})); 043 044 m_toRun = null; 045 046 for (Command command : m_commands.values()) { 047 m_requirements.addAll(command.getRequirements()); 048 m_runsWhenDisabled &= command.runsWhenDisabled(); 049 if (command.getInterruptionBehavior() == InterruptionBehavior.kCancelSelf) { 050 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 051 } 052 } 053 } 054 055 /** 056 * Creates a new SelectCommand. 057 * 058 * @param toRun a supplier providing the command to run 059 * @deprecated Replace with {@link ProxyCommand} 060 */ 061 @Deprecated 062 public SelectCommand(Supplier<Command> toRun) { 063 m_commands = null; 064 m_selector = null; 065 m_toRun = requireNonNullParam(toRun, "toRun", "SelectCommand"); 066 067 // we have no way of checking the underlying command, so default. 068 m_runsWhenDisabled = false; 069 m_interruptBehavior = InterruptionBehavior.kCancelSelf; 070 } 071 072 @Override 073 public void initialize() { 074 if (m_selector != null) { 075 if (!m_commands.containsKey(m_selector.get())) { 076 m_selectedCommand = 077 new PrintCommand( 078 "SelectCommand selector value does not correspond to" + " any command!"); 079 return; 080 } 081 m_selectedCommand = m_commands.get(m_selector.get()); 082 } else { 083 m_selectedCommand = m_toRun.get(); 084 } 085 m_selectedCommand.initialize(); 086 } 087 088 @Override 089 public void execute() { 090 m_selectedCommand.execute(); 091 } 092 093 @Override 094 public void end(boolean interrupted) { 095 m_selectedCommand.end(interrupted); 096 } 097 098 @Override 099 public boolean isFinished() { 100 return m_selectedCommand.isFinished(); 101 } 102 103 @Override 104 public boolean runsWhenDisabled() { 105 return m_runsWhenDisabled; 106 } 107 108 @Override 109 public InterruptionBehavior getInterruptionBehavior() { 110 return m_interruptBehavior; 111 } 112 113 @Override 114 public void initSendable(SendableBuilder builder) { 115 super.initSendable(builder); 116 117 builder.addStringProperty( 118 "selected", () -> m_selectedCommand == null ? "null" : m_selectedCommand.getName(), null); 119 } 120}