package envoy.client.ui.chatscene; import java.util.Random; import java.util.function.*; import java.util.logging.Level; import javafx.scene.control.ListView; import javafx.scene.control.skin.VirtualFlow; import envoy.client.data.Context; import envoy.client.data.commands.*; import envoy.client.helper.ShutdownHelper; import envoy.client.ui.SceneContext.SceneInfo; import envoy.client.ui.controller.ChatScene; import envoy.client.util.MessageUtil; import envoy.data.Message; import envoy.util.EnvoyLog; /** * Contains all {@link SystemCommand}s used for * {@link envoy.client.ui.controller.ChatScene}. * * @author Leon Hofmeister * @since Envoy Client v0.3-beta */ public final class ChatSceneCommands { private final ListView messageList; private final SystemCommandMap messageTextAreaCommands = new SystemCommandMap(); private final SystemCommandBuilder builder = new SystemCommandBuilder(messageTextAreaCommands); private static final String messageDependantCommandDescription = " the given message. Use s/S to use the selected message. Otherwise expects a number relative to the uppermost completely visible message."; /** * * @param messageList the message list to use for some commands * @param chatScene the instance of {@code ChatScene} that uses this object * @since Envoy Client v0.3-beta */ public ChatSceneCommands(ListView messageList, ChatScene chatScene) { this.messageList = messageList; // Do A Barrel roll initialization final var random = new Random(); builder.setAction(text -> chatScene.doABarrelRoll(Integer.parseInt(text.get(0)), Double.parseDouble(text.get(1)))) .setDefaults(Integer.toString(random.nextInt(3) + 1), Double.toString(random.nextDouble() * 3 + 1)) .setDescription("See for yourself :)") .setNumberOfArguments(2) .build("dabr"); // Logout initialization builder.setAction(text -> ShutdownHelper.logout()).setDescription("Logs you out.").buildNoArg("logout"); // Exit initialization builder.setAction(text -> ShutdownHelper.exit()).setNumberOfArguments(0).setDescription("Exits the program.").build("exit", false); builder.build("q"); // Open settings scene initialization builder.setAction(text -> Context.getInstance().getSceneContext().load(SceneInfo.SETTINGS_SCENE)) .setDescription("Opens the settings screen") .buildNoArg("settings"); // Selection of a new message initialization messageDependantAction("s", m -> { messageList.getSelectionModel().clearSelection(); messageList.getSelectionModel().select(m); }, m -> true, "Selects"); // Copy text of selection initialization messageDependantAction("cp", MessageUtil::copyMessageText, m -> !m.getText().isEmpty(), "Copies the text of"); // Delete selection initialization messageDependantAction("del", MessageUtil::deleteMessage, m -> true, "Deletes"); // Save attachment of selection initialization messageDependantAction("save-att", MessageUtil::saveAttachment, Message::hasAttachment, "Saves the attachment of"); } private void messageDependantAction(String command, Consumer action, Predicate additionalCheck, String description) { builder.setAction(text -> { final var positionalArgument = text.get(0).toLowerCase(); // the currently selected message was requested if (positionalArgument.startsWith("s")) { final var relativeString = positionalArgument.length() == 1 ? "" : positionalArgument.substring(1); // Only s has been used as input if (positionalArgument.length() == 1) { final var selectedMessage = messageList.getSelectionModel().getSelectedItem(); if (selectedMessage != null && additionalCheck.test(selectedMessage)) action.accept(selectedMessage); return; // Either s++ or s-- has been requested } else if (relativeString.equals("++") || relativeString.equals("--")) selectionNeighbor(action, additionalCheck, positionalArgument); // A message relative to the currently selected message should be used (i.e. // s+4) else useRelativeMessage(command, action, additionalCheck, relativeString, true); // Either ++s or --s has been requested } else if (positionalArgument.equals("--s") || positionalArgument.equals("++s")) selectionNeighbor(action, additionalCheck, positionalArgument); // Just a number is expected: ((+)4) else useRelativeMessage(command, action, additionalCheck, positionalArgument, false); }).setDefaults("s").setNumberOfArguments(1).setDescription(description.concat(messageDependantCommandDescription)).build(command); } private void selectionNeighbor(Consumer action, Predicate additionalCheck, final String positionalArgument) { final var wantedIndex = messageList.getSelectionModel().getSelectedIndex() + (positionalArgument.contains("+") ? 1 : -1); messageList.getSelectionModel().clearAndSelect(wantedIndex); final var selectedMessage = messageList.getItems().get(wantedIndex); if (selectedMessage != null && additionalCheck.test(selectedMessage)) action.accept(selectedMessage); } private void useRelativeMessage(String command, Consumer action, Predicate additionalCheck, final String positionalArgument, boolean useSelectedMessage) throws NumberFormatException { final var stripPlus = positionalArgument.startsWith("+") ? positionalArgument.substring(1) : positionalArgument; final var incDec = Integer.valueOf(stripPlus); try { // The currently selected message is the base message if (useSelectedMessage) { final var messageToUse = messageList.getItems().get(messageList.getSelectionModel().getSelectedIndex() + incDec); if (messageToUse != null && additionalCheck.test(messageToUse)) action.accept(messageToUse); // The currently upmost completely visible message is the base message } else { final var messageToUse = messageList.getItems() .get(((VirtualFlow) messageList.lookup(".virtual-flow")).getFirstVisibleCell().getIndex() + 1 + incDec); if (messageToUse != null && additionalCheck.test(messageToUse)) action.accept(messageToUse); } } catch (final IndexOutOfBoundsException e) { EnvoyLog.getLogger(ChatSceneCommands.class) .log(Level.INFO, " A non-existing message was requested by the user for System command " + command); } } /** * @return the map used by this {@code ChatSceneCommands} * @since Envoy Client v0.3-beta */ public SystemCommandMap getChatSceneCommands() { return messageTextAreaCommands; } }