Move SystemComandMap from ChatScene to its own component
Additionally created message specific commands with their own parser and fixed separators not shown correctly in TextInputContextMenu
This commit is contained in:
		@@ -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">
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,8 +8,8 @@ import java.util.function.*;
 | 
				
			|||||||
 * 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.
 | 
				
			||||||
@@ -115,14 +115,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 : "") + "]";
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,9 +74,14 @@ public final class SystemCommandMap {
 | 
				
			|||||||
	 */
 | 
						 */
 | 
				
			||||||
	public String getCommand(String raw) {
 | 
						public String getCommand(String raw) {
 | 
				
			||||||
		final var trimmed = raw.stripLeading();
 | 
							final var trimmed = raw.stripLeading();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Entering only a slash should not throw an error
 | 
				
			||||||
 | 
							if (trimmed.length() == 1 && trimmed.charAt(0) == '/') return "";
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
			final var index = trimmed.indexOf(' ');
 | 
								final var index = trimmed.indexOf(' ');
 | 
				
			||||||
			return trimmed.substring(trimmed.charAt(0) == '/' ? 1 : 0, index < 1 ? trimmed.length() : index);
 | 
								return trimmed.substring(trimmed.charAt(0) == '/' ? 1 : 0, index < 1 ? trimmed.length() : index);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/**
 | 
						/**
 | 
				
			||||||
	 * Examines whether a key can be put in the map and logs it with
 | 
						 * Examines whether a key can be put in the map and logs it with
 | 
				
			||||||
@@ -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 "
 | 
				
			||||||
@@ -152,8 +157,19 @@ public final class SystemCommandMap {
 | 
				
			|||||||
			try {
 | 
								try {
 | 
				
			||||||
				systemCommand.getAction().accept(arguments);
 | 
									systemCommand.getAction().accept(arguments);
 | 
				
			||||||
				systemCommand.onCall();
 | 
									systemCommand.onCall();
 | 
				
			||||||
 | 
								} catch (final IndexOutOfBoundsException e) {
 | 
				
			||||||
 | 
									logger.log(Level.SEVERE,
 | 
				
			||||||
 | 
											String.format(
 | 
				
			||||||
 | 
													"System command %s threw an IndexOutOfBoundsException. The most likely cause is a lower number of arguments than expected. It could also be a problem of the action performed: ",
 | 
				
			||||||
 | 
													command),
 | 
				
			||||||
 | 
											e);
 | 
				
			||||||
 | 
								} 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 +257,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,13 +135,13 @@ 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