Move SystemComandMap From ChatScene to Its Own Component #74
| @@ -21,6 +21,7 @@ | |||||||
| 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"> | 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"> | ||||||
| 		<attributes> | 		<attributes> | ||||||
| 			<attribute name="maven.pomderived" value="true"/> | 			<attribute name="maven.pomderived" value="true"/> | ||||||
|  | 			<attribute name="module" value="true"/> | ||||||
| 		</attributes> | 		</attributes> | ||||||
| 	</classpathentry> | 	</classpathentry> | ||||||
| 	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | 	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"> | ||||||
|   | |||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | package envoy.client.data.commands; | ||||||
|  |  | ||||||
|  | import java.util.List; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This interface defines an action that should be performed when a system | ||||||
|  |  * command gets called. | ||||||
|  |  * | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @since Envoy Client v0.2-beta | ||||||
|  |  */ | ||||||
|  | public interface Callable { | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * Performs the instance specific action when a {@link SystemCommand} has been | ||||||
|  | 	 * called. | ||||||
|  | 	 * | ||||||
|  | 	 * @param arguments the arguments that should be passed to the | ||||||
|  | 	 *                  {@link SystemCommand} | ||||||
|  | 	 * @since Envoy Client v0.2-beta | ||||||
|  | 	 */ | ||||||
|  | 	void call(List<String> arguments); | ||||||
|  | } | ||||||
| @@ -1,30 +0,0 @@ | |||||||
| package envoy.client.data.commands; |  | ||||||
|  |  | ||||||
| import java.util.function.Supplier; |  | ||||||
|  |  | ||||||
| /** |  | ||||||
|  * This interface defines an action that should be performed when a system |  | ||||||
|  * command gets called. |  | ||||||
|  * |  | ||||||
|  * @author Leon Hofmeister |  | ||||||
|  * @since Envoy Client v0.2-beta |  | ||||||
|  */ |  | ||||||
| public interface OnCall { |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Performs class specific actions when a {@link SystemCommand} has been called. |  | ||||||
| 	 * |  | ||||||
| 	 * @since Envoy Client v0.2-beta |  | ||||||
| 	 */ |  | ||||||
| 	void onCall(); |  | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Performs actions that can only be performed by classes that are not |  | ||||||
| 	 * {@link SystemCommand}s when a SystemCommand has been called. |  | ||||||
| 	 * |  | ||||||
| 	 * @param consumer the action to perform when this {@link SystemCommand} has |  | ||||||
| 	 *                 been called |  | ||||||
| 	 * @since Envoy Client v0.2-beta |  | ||||||
| 	 */ |  | ||||||
| 	void onCall(Supplier<Void> consumer); |  | ||||||
| } |  | ||||||
| @@ -1,15 +1,15 @@ | |||||||
| package envoy.client.data.commands; | package envoy.client.data.commands; | ||||||
|  |  | ||||||
| import java.util.*; | import java.util.*; | ||||||
| import java.util.function.*; | import java.util.function.Consumer; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * This class is the base class of all {@code SystemCommands} and contains an |  * This class is the base class of all {@code SystemCommands} and contains an | ||||||
|  * action and a number of arguments that should be used as input for this |  * action and a number of arguments that should be used as input for this | ||||||
|  * function. |  * function. | ||||||
|  * No {@code SystemCommand} can return anything. |  * No {@code SystemCommand} can return anything. | ||||||
|  * Every {@code SystemCommand} must have as argument type {@code List<String>} so |  * Every {@code SystemCommand} must have as argument type {@code List<String>} | ||||||
|  * that the words following the indicator String can be used as input of the |  * so that the words following the indicator String can be used as input of the | ||||||
|  * function. This approach has one limitation:<br> |  * function. This approach has one limitation:<br> | ||||||
|  * <b>Order matters!</b> Changing the order of arguments will likely result in |  * <b>Order matters!</b> Changing the order of arguments will likely result in | ||||||
|  * unexpected behavior. |  * unexpected behavior. | ||||||
| @@ -17,7 +17,7 @@ import java.util.function.*; | |||||||
|  * @author Leon Hofmeister |  * @author Leon Hofmeister | ||||||
|  * @since Envoy Client v0.2-beta |  * @since Envoy Client v0.2-beta | ||||||
|  */ |  */ | ||||||
| public final class SystemCommand implements OnCall { | public final class SystemCommand implements Callable { | ||||||
|  |  | ||||||
| 	protected int relevance; | 	protected int relevance; | ||||||
|  |  | ||||||
| @@ -55,12 +55,6 @@ public final class SystemCommand implements OnCall { | |||||||
| 		this.description		= description; | 		this.description		= description; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * @return the action that should be performed |  | ||||||
| 	 * @since Envoy Client v0.2-beta |  | ||||||
| 	 */ |  | ||||||
| 	public Consumer<List<String>> getAction() { return action; } |  | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the argument count of the command | 	 * @return the argument count of the command | ||||||
| 	 * @since Envoy Client v0.2-beta | 	 * @since Envoy Client v0.2-beta | ||||||
| @@ -85,20 +79,10 @@ public final class SystemCommand implements OnCall { | |||||||
| 	 */ | 	 */ | ||||||
| 	public void setRelevance(int relevance) { this.relevance = relevance; } | 	public void setRelevance(int relevance) { this.relevance = relevance; } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Increments the relevance of this {@code SystemCommand}. |  | ||||||
| 	 */ |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onCall() { relevance++; } | 	public void call(List<String> arguments) { | ||||||
|  | 		action.accept(arguments); | ||||||
| 	/** | 		++relevance; | ||||||
| 	 * Increments the relevance of this {@code SystemCommand} and executes the |  | ||||||
| 	 * supplier. |  | ||||||
| 	 */ |  | ||||||
| 	@Override |  | ||||||
| 	public void onCall(Supplier<Void> consumer) { |  | ||||||
| 		onCall(); |  | ||||||
| 		consumer.get(); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -115,14 +99,13 @@ public final class SystemCommand implements OnCall { | |||||||
| 		if (this == obj) return true; | 		if (this == obj) return true; | ||||||
| 		if (obj == null) return false; | 		if (obj == null) return false; | ||||||
| 		if (getClass() != obj.getClass()) return false; | 		if (getClass() != obj.getClass()) return false; | ||||||
| 		final SystemCommand other = (SystemCommand) obj; | 		final var other = (SystemCommand) obj; | ||||||
| 		return Objects.equals(action, other.action); | 		return Objects.equals(action, other.action); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public String toString() { | 	public String toString() { | ||||||
| 		return "SystemCommand [relevance=" + relevance + ", numberOfArguments=" + numberOfArguments + ", " | 		return "SystemCommand [relevance=" + relevance + ", numberOfArguments=" + numberOfArguments + ", " | ||||||
| 				+ (action != null ? "action=" + action + ", " : "") + (description != null ? "description=" + description + ", " : "") | 				+ (description != null ? "description=" + description + ", " : "") + (defaults != null ? "defaults=" + defaults : "") + "]"; | ||||||
| 				+ (defaults != null ? "defaults=" + defaults : "") + "]"; |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -73,9 +73,14 @@ public final class SystemCommandMap { | |||||||
| 	 *          exception: for recommendation purposes. | 	 *          exception: for recommendation purposes. | ||||||
| 	 */ | 	 */ | ||||||
| 	public String getCommand(String raw) { | 	public String getCommand(String raw) { | ||||||
| 		final var	trimmed	= raw.stripLeading(); | 		final var trimmed = raw.stripLeading(); | ||||||
| 		final var	index	= trimmed.indexOf(' '); |  | ||||||
| 		return trimmed.substring(trimmed.charAt(0) == '/' ? 1 : 0, index < 1 ? trimmed.length() : index); | 		// Entering only a slash should not throw an error | ||||||
|  | 		if (trimmed.length() == 1 && trimmed.charAt(0) == '/') return ""; | ||||||
|  | 		else { | ||||||
|  | 			final var index = trimmed.indexOf(' '); | ||||||
|  | 			return trimmed.substring(trimmed.charAt(0) == '/' ? 1 : 0, index < 1 ? trimmed.length() : index); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| @@ -92,7 +97,7 @@ public final class SystemCommandMap { | |||||||
| 	 * @since Envoy Client v0.2-beta | 	 * @since Envoy Client v0.2-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	public boolean isValidKey(String command) { | 	public boolean isValidKey(String command) { | ||||||
| 		final boolean valid = commandPattern.matcher(command).matches(); | 		final var valid = commandPattern.matcher(command).matches(); | ||||||
| 		if (!valid) logger.log(Level.WARNING, | 		if (!valid) logger.log(Level.WARNING, | ||||||
| 				"The command \"" + command | 				"The command \"" + command | ||||||
| 						+ "\" is not valid. As it will cause problems in execution, it will not be entered into the map. Only the characters " | 						+ "\" is not valid. As it will cause problems in execution, it will not be entered into the map. Only the characters " | ||||||
| @@ -150,10 +155,14 @@ public final class SystemCommandMap { | |||||||
| 			final var arguments = extractArguments(input, systemCommand); | 			final var arguments = extractArguments(input, systemCommand); | ||||||
| 			// Executing the function | 			// Executing the function | ||||||
| 			try { | 			try { | ||||||
| 				systemCommand.getAction().accept(arguments); | 				systemCommand.call(arguments); | ||||||
| 				systemCommand.onCall(); | 			} catch (final NumberFormatException e) { | ||||||
|  | 				logger.log(Level.INFO, | ||||||
|  | 						String.format( | ||||||
|  | 								"System command %s could not be performed correctly because the user is a dumbass and could not write a parseable number.", | ||||||
|  | 								command)); | ||||||
| 			} catch (final Exception e) { | 			} catch (final Exception e) { | ||||||
| 				logger.log(Level.WARNING, "The system command " + command + " threw an exception: ", e); | 				logger.log(Level.WARNING, "System command " + command + " threw an exception: ", e); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}); | ||||||
| 		return value.isPresent(); | 		return value.isPresent(); | ||||||
| @@ -241,7 +250,7 @@ public final class SystemCommandMap { | |||||||
| 		final var			numberOfArguments	= toEvaluate.getNumberOfArguments(); | 		final var			numberOfArguments	= toEvaluate.getNumberOfArguments(); | ||||||
| 		final List<String>	result				= new ArrayList<>(); | 		final List<String>	result				= new ArrayList<>(); | ||||||
|  |  | ||||||
| 		if (toEvaluate.getNumberOfArguments() > 0) for (int index = 0; index < numberOfArguments; index++) { | 		if (toEvaluate.getNumberOfArguments() > 0) for (var index = 0; index < numberOfArguments; index++) { | ||||||
| 			String textArg = null; | 			String textArg = null; | ||||||
| 			if (index < textArguments.length) textArg = textArguments[index]; | 			if (index < textArguments.length) textArg = textArguments[index]; | ||||||
| 			// Set the argument at position index to the current argument of the text, if it | 			// Set the argument at position index to the current argument of the text, if it | ||||||
|   | |||||||
| @@ -0,0 +1,144 @@ | |||||||
|  | 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<Message>		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<Message> 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<Message> action, Predicate<Message> 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<Message> action, Predicate<Message> 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<Message> action, Predicate<Message> 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; } | ||||||
|  | } | ||||||
| @@ -1,4 +1,4 @@ | |||||||
| package envoy.client.ui.control; | package envoy.client.ui.chatscene; | ||||||
| 
 | 
 | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| 
 | 
 | ||||||
| @@ -38,7 +38,6 @@ public class TextInputContextMenu extends ContextMenu { | |||||||
| 	private final MenuItem	deleteMI	= new MenuItem("Delete selection"); | 	private final MenuItem	deleteMI	= new MenuItem("Delete selection"); | ||||||
| 	private final MenuItem	clearMI		= new MenuItem("Clear"); | 	private final MenuItem	clearMI		= new MenuItem("Clear"); | ||||||
| 	private final MenuItem	selectAllMI	= new MenuItem("Select all"); | 	private final MenuItem	selectAllMI	= new MenuItem("Select all"); | ||||||
| 	private final MenuItem	separatorMI	= new SeparatorMenuItem(); |  | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Creates a new {@code TextInputContextMenu} with an optional action when | 	 * Creates a new {@code TextInputContextMenu} with an optional action when | ||||||
| @@ -90,13 +89,14 @@ public class TextInputContextMenu extends ContextMenu { | |||||||
| 		// Add all items to the ContextMenu | 		// Add all items to the ContextMenu | ||||||
| 		getItems().add(undoMI); | 		getItems().add(undoMI); | ||||||
| 		getItems().add(redoMI); | 		getItems().add(redoMI); | ||||||
|  | 		getItems().add(new SeparatorMenuItem()); | ||||||
| 		getItems().add(cutMI); | 		getItems().add(cutMI); | ||||||
| 		getItems().add(copyMI); | 		getItems().add(copyMI); | ||||||
| 		getItems().add(pasteMI); | 		getItems().add(pasteMI); | ||||||
| 		getItems().add(separatorMI); | 		getItems().add(new SeparatorMenuItem()); | ||||||
| 		getItems().add(deleteMI); | 		getItems().add(deleteMI); | ||||||
| 		getItems().add(clearMI); | 		getItems().add(clearMI); | ||||||
| 		getItems().add(separatorMI); | 		getItems().add(new SeparatorMenuItem()); | ||||||
| 		getItems().add(selectAllMI); | 		getItems().add(selectAllMI); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @@ -0,0 +1,7 @@ | |||||||
|  | /** | ||||||
|  |  * Contains classes that influence the appearance and behavior of ChatScene. | ||||||
|  |  *  | ||||||
|  |  * @author Leon Hofmeister | ||||||
|  |  * @since Envoy Client v0.3-beta | ||||||
|  |  */ | ||||||
|  | package envoy.client.ui.chatscene; | ||||||
| @@ -6,7 +6,6 @@ import java.io.*; | |||||||
| import java.nio.file.Files; | import java.nio.file.Files; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
| import java.time.format.DateTimeFormatter; | import java.time.format.DateTimeFormatter; | ||||||
| import java.util.Random; |  | ||||||
| import java.util.logging.*; | import java.util.logging.*; | ||||||
|  |  | ||||||
| import javafx.animation.RotateTransition; | import javafx.animation.RotateTransition; | ||||||
| @@ -26,13 +25,11 @@ import javafx.util.Duration; | |||||||
|  |  | ||||||
| import envoy.client.data.*; | import envoy.client.data.*; | ||||||
| import envoy.client.data.audio.AudioRecorder; | import envoy.client.data.audio.AudioRecorder; | ||||||
| import envoy.client.data.commands.*; |  | ||||||
| import envoy.client.event.*; | import envoy.client.event.*; | ||||||
| import envoy.client.helper.ShutdownHelper; |  | ||||||
| import envoy.client.net.*; | import envoy.client.net.*; | ||||||
| import envoy.client.ui.*; | import envoy.client.ui.*; | ||||||
| import envoy.client.ui.SceneContext.SceneInfo; | import envoy.client.ui.chatscene.*; | ||||||
| import envoy.client.ui.control.*; | import envoy.client.ui.control.ChatControl; | ||||||
| import envoy.client.ui.listcell.*; | import envoy.client.ui.listcell.*; | ||||||
| import envoy.client.util.*; | import envoy.client.util.*; | ||||||
| import envoy.data.*; | import envoy.data.*; | ||||||
| @@ -138,14 +135,14 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 	private Attachment			pendingAttachment; | 	private Attachment			pendingAttachment; | ||||||
| 	private boolean				postingPermanentlyDisabled; | 	private boolean				postingPermanentlyDisabled; | ||||||
| 	private boolean				isCustomAttachmentImage; | 	private boolean				isCustomAttachmentImage; | ||||||
|  | 	private ChatSceneCommands	commands; | ||||||
|  |  | ||||||
| 	private final LocalDB			localDB					= context.getLocalDB(); | 	private final LocalDB		localDB				= context.getLocalDB(); | ||||||
| 	private final Client			client					= context.getClient(); | 	private final Client		client				= context.getClient(); | ||||||
| 	private final WriteProxy		writeProxy				= context.getWriteProxy(); | 	private final WriteProxy	writeProxy			= context.getWriteProxy(); | ||||||
| 	private final SceneContext		sceneContext			= context.getSceneContext(); | 	private final SceneContext	sceneContext		= context.getSceneContext(); | ||||||
| 	private final AudioRecorder		recorder				= new AudioRecorder(); | 	private final AudioRecorder	recorder			= new AudioRecorder(); | ||||||
| 	private final SystemCommandMap	messageTextAreaCommands	= new SystemCommandMap(); | 	private final Tooltip		onlyIfOnlineTooltip	= new Tooltip("You need to be online to do this"); | ||||||
| 	private final Tooltip			onlyIfOnlineTooltip		= new Tooltip("You need to be online to do this"); |  | ||||||
|  |  | ||||||
| 	private static Image DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20); | 	private static Image DEFAULT_ATTACHMENT_VIEW_IMAGE = IconUtil.loadIconThemeSensitive("attachment_present", 20); | ||||||
|  |  | ||||||
| @@ -164,6 +161,7 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 	@FXML | 	@FXML | ||||||
| 	private void initialize() { | 	private void initialize() { | ||||||
| 		eventBus.registerListener(this); | 		eventBus.registerListener(this); | ||||||
|  | 		commands = new ChatSceneCommands(messageList, this); | ||||||
|  |  | ||||||
| 		// Initialize message and user rendering | 		// Initialize message and user rendering | ||||||
| 		messageList.setCellFactory(MessageListCell::new); | 		messageList.setCellFactory(MessageListCell::new); | ||||||
| @@ -192,8 +190,6 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 		chatList.setItems(chats = new FilteredList<>(localDB.getChats())); | 		chatList.setItems(chats = new FilteredList<>(localDB.getChats())); | ||||||
| 		contactLabel.setText(localDB.getUser().getName()); | 		contactLabel.setText(localDB.getUser().getName()); | ||||||
|  |  | ||||||
| 		initializeSystemCommandsMap(); |  | ||||||
|  |  | ||||||
| 		Platform.runLater(() -> { | 		Platform.runLater(() -> { | ||||||
| 			final var online = client.isOnline(); | 			final var online = client.isOnline(); | ||||||
| 			// no check will be performed in case it has already been disabled - a negative | 			// no check will be performed in case it has already been disabled - a negative | ||||||
| @@ -308,54 +304,6 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 	@Event(eventType = Logout.class, priority = 200) | 	@Event(eventType = Logout.class, priority = 200) | ||||||
| 	private void onLogout() { eventBus.removeListener(this); } | 	private void onLogout() { eventBus.removeListener(this); } | ||||||
|  |  | ||||||
| 	/** |  | ||||||
| 	 * Initializes all {@code SystemCommands} used in {@code ChatScene}. |  | ||||||
| 	 * |  | ||||||
| 	 * @since Envoy Client v0.2-beta |  | ||||||
| 	 */ |  | ||||||
| 	private void initializeSystemCommandsMap() { |  | ||||||
| 		final var builder = new SystemCommandBuilder(messageTextAreaCommands); |  | ||||||
|  |  | ||||||
| 		// Do A Barrel roll initialization |  | ||||||
| 		final var random = new Random(); |  | ||||||
| 		builder.setAction(text -> 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()).setNumberOfArguments(0).setDescription("Logs you out.").build("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 -> sceneContext.load(SceneInfo.SETTINGS_SCENE)) |  | ||||||
| 			.setNumberOfArguments(0) |  | ||||||
| 			.setDescription("Opens the settings screen") |  | ||||||
| 			.build("settings"); |  | ||||||
|  |  | ||||||
| 		// Copy text of selection initialization |  | ||||||
| 		builder.setAction(text -> { |  | ||||||
| 			final var selectedMessage = messageList.getSelectionModel().getSelectedItem(); |  | ||||||
| 			if (selectedMessage != null) MessageUtil.copyMessageText(selectedMessage); |  | ||||||
| 		}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("cp-s"); |  | ||||||
|  |  | ||||||
| 		// Delete selection initialization |  | ||||||
| 		builder.setAction(text -> { |  | ||||||
| 			final var selectedMessage = messageList.getSelectionModel().getSelectedItem(); |  | ||||||
| 			if (selectedMessage != null) MessageUtil.deleteMessage(selectedMessage); |  | ||||||
| 		}).setNumberOfArguments(0).setDescription("Deletes the currently selected message").build("del-s"); |  | ||||||
|  |  | ||||||
| 		// Save attachment of selection initialization |  | ||||||
| 		builder.setAction(text -> { |  | ||||||
| 			final var selectedMessage = messageList.getSelectionModel().getSelectedItem(); |  | ||||||
| 			if (selectedMessage != null && selectedMessage.hasAttachment()) MessageUtil.saveAttachment(selectedMessage); |  | ||||||
| 		}).setNumberOfArguments(0).setDescription("Copies the text of the currently selected message").build("save-a-s"); |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	@Override | 	@Override | ||||||
| 	public void onRestore() { updateRemainingCharsLabel(); } | 	public void onRestore() { updateRemainingCharsLabel(); } | ||||||
|  |  | ||||||
| @@ -530,7 +478,7 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 	 * @param animationTime the time in seconds that this animation lasts | 	 * @param animationTime the time in seconds that this animation lasts | ||||||
| 	 * @since Envoy Client v0.1-beta | 	 * @since Envoy Client v0.1-beta | ||||||
| 	 */ | 	 */ | ||||||
| 	private void doABarrelRoll(int rotations, double animationTime) { | 	public void doABarrelRoll(int rotations, double animationTime) { | ||||||
| 		// Limiting the rotations and duration | 		// Limiting the rotations and duration | ||||||
| 		rotations		= Math.min(rotations, 100000); | 		rotations		= Math.min(rotations, 100000); | ||||||
| 		rotations		= Math.max(rotations, 1); | 		rotations		= Math.max(rotations, 1); | ||||||
| @@ -677,7 +625,7 @@ public final class ChatScene implements EventListener, Restorable { | |||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
| 		final var text = messageTextArea.getText().strip(); | 		final var text = messageTextArea.getText().strip(); | ||||||
| 		if (!messageTextAreaCommands.executeIfAnyPresent(text)) { | 		if (!commands.getChatSceneCommands().executeIfAnyPresent(text)) { | ||||||
| 			// Creating the message and its metadata | 			// Creating the message and its metadata | ||||||
| 			final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator()) | 			final var builder = new MessageBuilder(localDB.getUser().getID(), currentChat.getRecipient().getID(), localDB.getIDGenerator()) | ||||||
| 				.setText(text); | 				.setText(text); | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ module envoy.client { | |||||||
|  |  | ||||||
| 	opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus; | 	opens envoy.client.ui to javafx.graphics, javafx.fxml, dev.kske.eventbus; | ||||||
| 	opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus; | 	opens envoy.client.ui.controller to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus; | ||||||
|  | 	opens envoy.client.ui.chatscene to javafx.graphics, javafx.fxml, envoy.client.util, dev.kske.eventbus; | ||||||
| 	opens envoy.client.ui.control to javafx.graphics, javafx.fxml; | 	opens envoy.client.ui.control to javafx.graphics, javafx.fxml; | ||||||
| 	opens envoy.client.ui.settings to envoy.client.util; | 	opens envoy.client.ui.settings to envoy.client.util; | ||||||
| 	opens envoy.client.net to dev.kske.eventbus; | 	opens envoy.client.net to dev.kske.eventbus; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user