diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java index ed77f5c6c..092345ef7 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/AbstractView.java @@ -17,6 +17,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.function.BiFunction; import java.util.function.Predicate; @@ -55,6 +56,7 @@ public abstract class AbstractView extends AbstractControl implements View { private int layer; private EventLoop eventLoop; private ViewService viewService; + private final Map commands = new HashMap<>(); private Map keyBindings = new HashMap<>(); private Map hotKeyBindings = new HashMap<>(); private Map mouseBindings = new HashMap<>(); @@ -173,7 +175,7 @@ public KeyHandler getKeyHandler() { if (key != null) { KeyBindingValue keyBindingValue = getKeyBindings().get(key); if (keyBindingValue != null) { - consumed = dispatchRunCommand(event, keyBindingValue); + consumed = dispatchKeyRunCommand(event, keyBindingValue); } } @@ -192,7 +194,7 @@ public KeyHandler getHotKeyHandler() { if (key != null) { KeyBindingValue keyBindingValue = getHotKeyBindings().get(key); if (keyBindingValue != null) { - consumed = dispatchRunCommand(event, keyBindingValue); + consumed = dispatchKeyRunCommand(event, keyBindingValue); } } @@ -257,6 +259,15 @@ protected ViewService getViewService() { return viewService; } + protected void registerViewCommand(String command, Runnable runnable) { + commands.put(command, runnable); + } + + @Override + public Set getViewCommands() { + return commands.keySet(); + } + protected void registerKeyBinding(Integer keyType, String keyCommand) { registerKeyBinding(keyType, keyCommand, null, null); } @@ -395,20 +406,43 @@ protected boolean dispatchRunnable(Runnable runnable) { return true; } - protected boolean dispatchRunCommand(KeyEvent event, KeyBindingValue command) { + @Override + public boolean runViewCommand(String command) { + if (eventLoop == null) { + return false; + } + if (command != null) { + Runnable runnable = commands.get(command); + if (runnable != null) { + Message message = ShellMessageBuilder + .withPayload(runnable) + .setEventType(EventLoop.Type.TASK) + .build(); + dispatch(message); + return true; + } + } + return false; + } + + protected boolean dispatchKeyRunCommand(KeyEvent event, KeyBindingValue keyBindingValue) { if (eventLoop == null) { return false; } - Runnable runnable = command.keyRunnable(); - if (runnable != null) { + String keyCommand = keyBindingValue.keyCommand(); + if (runViewCommand(keyCommand)) { + return true; + } + Runnable keyRunnable = keyBindingValue.keyRunnable(); + if (keyRunnable != null) { Message message = ShellMessageBuilder - .withPayload(runnable) + .withPayload(keyRunnable) .setEventType(EventLoop.Type.TASK) .build(); dispatch(message); return true; } - KeyBindingConsumer keyConsumer = command.keyConsumer(); + KeyBindingConsumer keyConsumer = keyBindingValue.keyConsumer(); if (keyConsumer != null) { Message message = ShellMessageBuilder .withPayload(new KeyBindingConsumerArgs(keyConsumer, event)) @@ -420,20 +454,24 @@ protected boolean dispatchRunCommand(KeyEvent event, KeyBindingValue command) { return false; } - protected boolean dispatchMouseRunCommand(MouseEvent event, MouseBindingValue command) { + protected boolean dispatchMouseRunCommand(MouseEvent event, MouseBindingValue mouseBindingValue) { if (eventLoop == null) { return false; } - Runnable runnable = command.mouseRunnable(); - if (runnable != null) { + String mouseCommand = mouseBindingValue.mouseCommand(); + if (runViewCommand(mouseCommand)) { + return true; + } + Runnable mouseRunnable = mouseBindingValue.mouseRunnable(); + if (mouseRunnable != null) { Message message = ShellMessageBuilder - .withPayload(runnable) + .withPayload(mouseRunnable) .setEventType(EventLoop.Type.TASK) .build(); dispatch(message); return true; } - MouseBindingConsumer mouseConsumer = command.mouseConsumer(); + MouseBindingConsumer mouseConsumer = mouseBindingValue.mouseConsumer(); if (mouseConsumer != null) { Message message = ShellMessageBuilder .withPayload(new MouseBindingConsumerArgs(mouseConsumer, event)) diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ListView.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ListView.java index 583fa831b..7a802fbd7 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ListView.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ListView.java @@ -38,6 +38,12 @@ /** * {@code ListView} is a {@link View} showing items in a vertical list. * + *

Supported view commands: + *

    + *
  • {@link ViewCommand#LINE_UP} - Move active line upwards. + *
  • {@link ViewCommand#LINE_DOWN} - Move active line downwards. + *
+ * * @author Janne Valkealahti */ public class ListView extends BoxView { @@ -94,13 +100,16 @@ public ListView(@Nullable List items, ItemStyle itemStyle) { @Override protected void initInternal() { - registerKeyBinding(Key.CursorUp, () -> up()); - registerKeyBinding(Key.CursorDown, () -> down()); + registerViewCommand(ViewCommand.LINE_UP, () -> up()); + registerViewCommand(ViewCommand.LINE_DOWN, () -> down()); + + registerKeyBinding(Key.CursorUp, ViewCommand.LINE_UP); + registerKeyBinding(Key.CursorDown, ViewCommand.LINE_DOWN); registerKeyBinding(Key.Enter, () -> enter()); registerKeyBinding(Key.Space, () -> space()); - registerMouseBinding(MouseEvent.Type.Wheel | MouseEvent.Button.WheelUp, () -> up()); - registerMouseBinding(MouseEvent.Type.Wheel | MouseEvent.Button.WheelDown, () -> down()); + registerMouseBinding(MouseEvent.Type.Wheel | MouseEvent.Button.WheelUp, ViewCommand.LINE_UP); + registerMouseBinding(MouseEvent.Type.Wheel | MouseEvent.Button.WheelDown, ViewCommand.LINE_DOWN); registerMouseBinding(MouseEvent.Type.Released | MouseEvent.Button.Button1, event -> click(event)); } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/View.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/View.java index 412b5f155..aff2e8e93 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/View.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/View.java @@ -15,6 +15,8 @@ */ package org.springframework.shell.component.view.control; +import java.util.Set; + import org.springframework.lang.Nullable; import org.springframework.shell.component.view.event.EventLoop; import org.springframework.shell.component.view.event.KeyHandler; @@ -87,4 +89,20 @@ public interface View extends Control { */ void setEventLoop(@Nullable EventLoop eventLoop); + /** + * Get supported commands. + * + * @return supported commands + * @see ViewCommand + */ + Set getViewCommands(); + + /** + * Run command. + * + * @param command the command to run + * @return true if command was succesfully dispatched + * @see ViewCommand + */ + boolean runViewCommand(String command); } diff --git a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ViewCommand.java b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ViewCommand.java index c3c0982c7..d46d2e1e3 100644 --- a/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ViewCommand.java +++ b/spring-shell-core/src/main/java/org/springframework/shell/component/view/control/ViewCommand.java @@ -26,25 +26,17 @@ public final class ViewCommand { /** - * Move line up. Generic use in something where selection needs to be moved up. + * Move line up. + * + * For example where selection needs to be moved up. */ public static String LINE_UP = "LineUp"; /** - * Move line down. Generic use in something where selection needs to be moved - * down. + * Move line down. + * + * For example where selection needs to be moved down. */ public static String LINE_DOWN = "LineDown"; - /** - * Open selected item. In a some sort of view where something can be selected - * and that active selected should be opened. - */ - public static String OPEN_SELECTED_ITEM = "OpenSelectedItem"; - - public static String SELECT = "Select"; - public static String LEFT = "Left"; - public static String RIGHT = "Right"; - public static String SELECTION_CHANGED = "SelectionChanged"; - } diff --git a/spring-shell-core/src/test/java/org/springframework/shell/component/view/control/ListViewTests.java b/spring-shell-core/src/test/java/org/springframework/shell/component/view/control/ListViewTests.java index 7abc9450f..2207e00dd 100644 --- a/spring-shell-core/src/test/java/org/springframework/shell/component/view/control/ListViewTests.java +++ b/spring-shell-core/src/test/java/org/springframework/shell/component/view/control/ListViewTests.java @@ -18,6 +18,7 @@ import java.time.Duration; import java.util.Arrays; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; @@ -474,4 +475,46 @@ public void draw(Screen screen) { } + @Nested + class ViewCommands { + + @BeforeEach + void setup() { + view = new ListView<>(); + configure(view); + view.setRect(0, 0, 80, 24); + view.setItems(Arrays.asList("item1", "item2")); + } + + @Test + void supports() { + assertThat(view.getViewCommands()).contains(ViewCommand.LINE_DOWN, ViewCommand.LINE_UP); + } + + @Test + void lineDown() { + StepVerifier verifier = StepVerifier.create(eventLoop.events()) + .expectNextCount(1) + .thenCancel() + .verifyLater(); + view.runViewCommand(ViewCommand.LINE_DOWN); + verifier.verify(Duration.ofSeconds(1)); + assertThat(getIntField(view, START_FIELD)).isEqualTo(0); + assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1); + } + + @Test + void lineUp() { + StepVerifier verifier = StepVerifier.create(eventLoop.events()) + .expectNextCount(1) + .thenCancel() + .verifyLater(); + view.runViewCommand(ViewCommand.LINE_UP); + verifier.verify(Duration.ofSeconds(1)); + assertThat(getIntField(view, START_FIELD)).isEqualTo(0); + assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1); + } + + } + }