Overhaul ListView to support checked states

- ListView can be defined to use nocheck, checked or radio
- List can now scroll through up/down
- Actual visual is handled in a DefaultListCell
- Modify/add scenarios and catalog app
- Relates #865
This commit is contained in:
Janne Valkealahti
2023-09-09 08:59:37 +03:00
parent a679de0067
commit 51c250608b
12 changed files with 971 additions and 195 deletions

View File

@@ -16,9 +16,15 @@
package org.springframework.shell.component.view.control;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.function.Function;
import java.util.ListIterator;
import java.util.Set;
import java.util.function.BiFunction;
import org.springframework.lang.Nullable;
import org.springframework.shell.component.view.control.cell.ListCell;
import org.springframework.shell.component.view.event.KeyEvent.Key;
import org.springframework.shell.component.view.event.MouseEvent;
@@ -27,69 +33,63 @@ import org.springframework.shell.component.view.message.ShellMessageBuilder;
import org.springframework.shell.component.view.screen.Screen;
import org.springframework.shell.component.view.screen.ScreenItem;
import org.springframework.shell.style.StyleSettings;
import org.springframework.util.Assert;
/**
* {@link ListView} shows {@code list items} vertically.
* {@code ListView} is a {@link View} showing items in a vertical list.
*
* @author Janne Valkealahti
*/
public class ListView<T> extends BoxView {
private final List<T> items = new ArrayList<>();
private int selected = -1;
private final List<ListCell<T>> cells = new ArrayList<>();
private Function<ListView<T>, ListCell<T>> factory = listView -> new ListCell<>();
private final ItemStyle itemStyle;
private int start = 0;
private int pos = 0;
private final Set<Integer> selected = new HashSet<>();
private BiFunction<ListView<T>, T, ListCell<T>> factory = (listView, item) -> ListCell.of(item,
listView.getItemStyle());
/**
* Construct list view with no initial items.
* Specifies how a item shows selection state.
*/
public enum ItemStyle {
/**
* The item will be shown normally, with no check indicator. The default.
*/
NOCHECK,
/**
* The item will indicate checked/un-checked state.
*/
CHECKED,
/**
* The item is part of a radio group and will indicate selected state.
*/
RADIO
}
public ListView() {
this.itemStyle = ItemStyle.NOCHECK;
}
@Override
protected void drawInternal(Screen screen) {
Rectangle rect = getInnerRect();
int y = rect.y();
int selectedStyle = resolveThemeStyle(StyleSettings.TAG_HIGHLIGHT, ScreenItem.STYLE_BOLD);
int i = 0;
for (ListCell<T> c : cells) {
c.setRect(rect.x(), y++, rect.width(), 1);
if (i == selected) {
c.updateSelected(true);
c.setStyle(selectedStyle);
}
else {
c.updateSelected(false);
c.setBackgroundColor(-1);
c.setStyle(-1);
}
c.updateSelected(i == selected);
c.draw(screen);
i++;
}
super.drawInternal(screen);
public ListView(ItemStyle itemStyle) {
Assert.notNull(itemStyle, "item style must be set");
this.itemStyle = itemStyle;
setItems(null);
}
/**
* Sets a cell factory.
*
* @param factory the cell factory
*/
public void setCellFactory(Function<ListView<T>, ListCell<T>> factory) {
this.factory = factory;
public ListView(T[] items, ItemStyle itemStyle) {
this(items != null ? Arrays.asList(items) : Collections.emptyList(), itemStyle);
}
public void setItems(List<T> items) {
this.items.clear();
this.items.addAll(items);
this.cells.clear();
for (T i : items) {
ListCell<T> c = factory.apply(this);
cells.add(c);
c.updateItem(i);
}
public ListView(@Nullable List<T> items, ItemStyle itemStyle) {
Assert.notNull(itemStyle, "item style must be set");
this.itemStyle = itemStyle;
setItems(items);
}
@Override
@@ -97,60 +97,187 @@ public class ListView<T> extends BoxView {
registerKeyBinding(Key.CursorUp, () -> up());
registerKeyBinding(Key.CursorDown, () -> 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.Released | MouseEvent.Button.Button1, event -> click(event));
}
private void up() {
updateIndex(-1);
dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem())));
public ItemStyle getItemStyle() {
return itemStyle;
}
private void down() {
updateIndex(1);
dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem())));
}
private void enter() {
dispatch(ShellMessageBuilder.ofView(this, ListViewOpenSelectedItemEvent.of(this, selectedItem())));
}
private void click(MouseEvent event) {
int index = event.y() - getInnerRect().y();
if (index > -1 && index < items.size()) {
setSelected(index);
private void updateCells() {
cells.clear();
for (T i : items) {
ListCell<T> c = factory.apply(this, i);
c.setItemStyle(getItemStyle());
cells.add(c);
}
}
public void setSelected(int selected) {
if (this.selected != selected) {
this.selected = selected;
public void setItems(@Nullable List<T> items) {
this.items.clear();
if (items != null) {
this.items.addAll(items);
}
if (this.items.isEmpty()) {
start = -1;
pos = -1;
}
else {
start = 0;
pos = 0;
}
updateCells();
}
private void updateSelectionStates() {
int active = start + pos;
if (itemStyle == ItemStyle.CHECKED) {
boolean removed = selected.remove(active);
if (!removed) {
selected.add(active);
}
}
else if (itemStyle == ItemStyle.RADIO) {
selected.clear();
selected.add(active);
}
ListIterator<ListCell<T>> iter = cells.listIterator();
while (iter.hasNext()) {
int index = iter.nextIndex();
ListCell<T> c = iter.next();
c.setSelected(selected.contains(index));
}
}
@Override
protected void drawInternal(Screen screen) {
if (start > -1 && pos > -1) {
Rectangle rect = getInnerRect();
int y = rect.y();
int selectedStyle = resolveThemeStyle(StyleSettings.TAG_HIGHLIGHT, ScreenItem.STYLE_BOLD);
int i = 0;
for (ListCell<T> c : cells) {
if (i < start) {
i++;
continue;
}
c.setRect(rect.x(), y++, rect.width(), 1);
if (i == start + pos) {
c.setStyle(selectedStyle);
}
else {
c.setBackgroundColor(-1);
c.setStyle(-1);
}
c.draw(screen);
i++;
if (i - start >= rect.height()) {
break;
}
}
}
super.drawInternal(screen);
}
public void setCellFactory(BiFunction<ListView<T>, T, ListCell<T>> factory) {
Assert.notNull(factory, "cell factory must be set");
this.factory = factory;
}
private void scrollIndex(boolean up) {
int size = items.size();
int maxItems = getInnerRect().height();
int active = start + pos;
if (up) {
if (start > 0 && pos == 0) {
start--;
}
else if (start + pos <= 0) {
start = size - Math.min(maxItems, size);
pos = Math.min(maxItems, size) - 1;
}
else {
pos--;
}
}
else {
if (start + pos + 1 < Math.min(maxItems, size)) {
pos++;
}
else if (start + pos + 1 >= size) {
start = 0;
pos = 0;
}
else {
start++;
}
}
if (active != start + pos) {
dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem())));
}
}
private void scrollIndex(int step) {
if (start < 0 && pos < 0) {
return;
}
if (step < 0) {
for (int i = step; i < 0; i++) {
scrollIndex(true);
}
}
else if (step > 0) {
for (int i = step; i > 0; i--) {
scrollIndex(false);
}
}
}
private T selectedItem() {
T selectedItem = null;
if (selected >= 0 && selected < items.size()) {
selectedItem = items.get(selected);
int active = start + pos;
if (active >= 0 && active < items.size()) {
selectedItem = items.get(active);
}
return selectedItem;
}
private void updateIndex(int step) {
int size = items.size();
if (step > 0) {
if (selected + step < size) {
selected += step;
}
}
else if (step < 0) {
if (selected - step > 0) {
selected += step;
private void up() {
scrollIndex(-1);
}
private void down() {
scrollIndex(1);
}
private void enter() {
if (itemStyle == ItemStyle.NOCHECK) {
dispatch(ShellMessageBuilder.ofView(this, ListViewOpenSelectedItemEvent.of(this, selectedItem())));
return;
}
}
private void space() {
updateSelectionStates();
}
private void click(MouseEvent event) {
int index = event.y() - getInnerRect().y();
int active = start + index;
if (active >= 0 && active < items.size()) {
pos = index;
if (itemStyle == ItemStyle.NOCHECK) {
dispatch(ShellMessageBuilder.ofView(this, ListViewSelectedItemChangedEvent.of(this, selectedItem())));
return;
}
}
updateSelectionStates();
}
/**

View File

@@ -16,16 +16,23 @@
package org.springframework.shell.component.view.control.cell;
import org.springframework.shell.component.view.control.AbstractControl;
import org.springframework.shell.component.view.control.Cell;
/**
* Base implementation of a {@link Cell}.
*
* @author Janne Valkealahti
*/
public abstract class AbstractCell<T> extends AbstractControl implements Cell<T> {
private boolean selected;
private T item;
private int style = -1;
private int foregroundColor = -1;
private int backgroundColor = -1;
public AbstractCell(T item) {
this.item = item;
}
@Override
public T getItem() {
return item;
@@ -36,16 +43,6 @@ public abstract class AbstractCell<T> extends AbstractControl implements Cell<T>
this.item = item;
}
@Override
public boolean isSelected() {
return selected;
}
@Override
public void updateSelected(boolean selected) {
this.selected = selected;
}
@Override
public void setStyle(int style) {
this.style = style;

View File

@@ -0,0 +1,88 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.component.view.control.cell;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
import org.springframework.shell.component.view.geom.Rectangle;
import org.springframework.shell.component.view.screen.Screen;
import org.springframework.shell.component.view.screen.Screen.Writer;
import org.springframework.util.StringUtils;
/**
* Base implementation of a {@link ListCell}.
*
* @author Janne Valkealahti
*/
public abstract class AbstractListCell<T> extends AbstractCell<T> implements ListCell<T> {
private ItemStyle itemStyle;
private boolean selected;
public AbstractListCell(T item) {
super(item);
}
public AbstractListCell(T item, ItemStyle itemStyle) {
super(item);
this.itemStyle = itemStyle;
}
protected String getText() {
return getItem().toString();
}
protected String getIndicator() {
if (getItemStyle() == ItemStyle.CHECKED || getItemStyle() == ItemStyle.RADIO) {
return selected ? "[x]" : "[ ]";
}
return null;
}
@Override
public void draw(Screen screen) {
String indicator = getIndicator();
String text = null;
if (StringUtils.hasText(indicator)) {
text = String.format("%s %s", indicator, getText());
}
else {
text = getText();
}
Rectangle rect = getRect();
Writer writer = screen.writerBuilder().style(getStyle()).color(getForegroundColor()).build();
writer.text(text, rect.x(), rect.y());
writer.background(rect, getBackgroundColor());
}
@Override
public void setItemStyle(ItemStyle itemStyle) {
this.itemStyle = itemStyle;
}
public ItemStyle getItemStyle() {
return itemStyle;
}
@Override
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
}

View File

@@ -0,0 +1,66 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.component.view.control.cell;
import org.springframework.shell.component.view.control.Control;
import org.springframework.shell.component.view.screen.Screen;
/**
* Base interface for all cells. Typically a {@link Cell} is a building block in
* a {@link View} not needing to be aware of how it is drawn into a {@link Screen}
* but needs to aware of its "item", bounds via {@link Control} and other
* properties like {@code background}.
*
* @author Janne Valkealahti
*/
public interface Cell<T> extends Control {
/**
* Get item bound to a cell.
*
* @return item bound to a cell
*/
T getItem();
/**
* Sets an item to bound into a cell.
*
* @param item item to bound into a cell
*/
void setItem(T item);
/**
* Sets a style.
*
* @param style the style
*/
void setStyle(int style);
/**
* Sets a foreground color.
*
* @param foregroundColor the background color
*/
void setForegroundColor(int foregroundColor);
/**
* Sets a background color.
*
* @param backgroundColor the background color
*/
void setBackgroundColor(int backgroundColor);
}

View File

@@ -15,32 +15,45 @@
*/
package org.springframework.shell.component.view.control.cell;
import org.springframework.shell.component.view.control.Cell;
import org.springframework.shell.component.view.control.ListView;
import org.springframework.shell.component.view.geom.Rectangle;
import org.springframework.shell.component.view.screen.Screen;
import org.springframework.shell.component.view.screen.Screen.Writer;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
/**
* The {@link Cell} type used within {@link ListView} instances
* Extension of a {@link Cell} to make it aware of an item style and selection state.
*
* @author Janne Valkealahti
*/
public class ListCell<T> extends AbstractCell<T> {
public interface ListCell<T> extends Cell<T> {
protected String text;
/**
* Set {@link ItemStyle}.
*
* @param itemStyle the item style
*/
void setItemStyle(ItemStyle itemStyle);
@Override
public void draw(Screen screen) {
Rectangle rect = getRect();
Writer writer = screen.writerBuilder().style(getStyle()).color(getForegroundColor()).build();
writer.text(text, rect.x(), rect.y());
writer.background(rect, getBackgroundColor());
/**
* Set selection state.
*
* @param selected the selection state
*/
void setSelected(boolean selected);
/**
* Helper method to build a {@code ListCell}.
*
* @param item the item
* @param itemStyle the item style
* @return a default list cell
*/
static <T> ListCell<T> of(T item, ItemStyle itemStyle) {
return new DefaultListCell<T>(item, itemStyle);
}
public void updateItem(T item) {
setItem(item);
this.text = item.toString();
}
static class DefaultListCell<T> extends AbstractListCell<T> {
DefaultListCell(T item, ItemStyle itemStyle) {
super(item, itemStyle);
}
}
}

View File

@@ -15,6 +15,8 @@
*/
package org.springframework.shell.component.view.control;
import java.util.Set;
import org.assertj.core.api.AssertProvider;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -56,6 +58,13 @@ public class AbstractViewTests {
eventLoop = null;
}
protected void clearScreens() {
screen24x80.resize(24, 80);
screen7x10.resize(7, 10);
screen0x0.resize(0, 0);
screen10x10.resize(10, 10);
}
protected void configure(View view) {
if (eventLoop != null) {
if (view instanceof AbstractView v) {
@@ -136,6 +145,11 @@ public class AbstractViewTests {
return getField(object, field, int.class);
}
@SuppressWarnings("unchecked")
protected static Set<Integer> getIntSetField(Object object, String field) {
return getField(object, field, Set.class);
}
protected static Runnable getRunnableField(Object object, String field) {
return getField(object, field, Runnable.class);
}
@@ -154,4 +168,12 @@ public class AbstractViewTests {
return (T) ReflectionTestUtils.invokeMethod(object, method, args);
}
protected static void callVoidIntMethod(Object target, String method, int value) {
ReflectionTestUtils.invokeSetterMethod(target, method, value, int.class);
}
protected static void callVoidMethod(Object target, String method) {
ReflectionTestUtils.invokeSetterMethod(target, method, null, null);
}
}

View File

@@ -15,12 +15,18 @@
*/
package org.springframework.shell.component.view.control;
import java.time.Duration;
import java.util.Arrays;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import org.springframework.shell.component.view.control.cell.ListCell;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
import org.springframework.shell.component.view.control.ListView.ListViewSelectedItemChangedEvent;
import org.springframework.shell.component.view.control.cell.AbstractListCell;
import org.springframework.shell.component.view.event.KeyEvent;
import org.springframework.shell.component.view.event.KeyEvent.Key;
import org.springframework.shell.component.view.event.KeyHandler;
@@ -31,104 +37,431 @@ import org.springframework.shell.component.view.event.MouseHandler.MouseHandlerR
import org.springframework.shell.component.view.geom.Rectangle;
import org.springframework.shell.component.view.screen.Screen;
import org.springframework.shell.component.view.screen.Screen.Writer;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat;
class ListViewTests extends AbstractViewTests {
@Test
void hasBorder() {
ListView<?> view = new ListView<>();
view.setShowBorder(true);
view.setRect(0, 0, 80, 24);
view.draw(screen24x80);
assertThat(forScreen(screen24x80)).hasBorder(0, 0, 80, 24);
private final static ParameterizedTypeReference<ListViewSelectedItemChangedEvent<String>> LISTVIEW_STRING_TYPEREF
= new ParameterizedTypeReference<ListViewSelectedItemChangedEvent<String>>() {};
private static final String SELECTED_FIELD = "selected";
private static final String START_FIELD = "start";
private static final String POSITION_FIELD = "pos";
private static final String SCROLL_METHOD = "scrollIndex";
ListView<String> view;
@Nested
class Events {
@Test
void arrowKeysMoveActive() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
Flux<ListViewSelectedItemChangedEvent<String>> actions = eventLoop
.viewEvents(LISTVIEW_STRING_TYPEREF);
StepVerifier verifier = StepVerifier.create(actions)
.expectNextCount(1)
.thenCancel()
.verifyLater();
KeyEvent eventDown = KeyEvent.of(Key.CursorDown);
KeyHandlerResult result = view.getKeyHandler().handle(KeyHandler.argsOf(eventDown));
assertThat(result).isNotNull().satisfies(r -> {
assertThat(r.event()).isEqualTo(eventDown);
assertThat(r.consumed()).isTrue();
});
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
verifier.verify(Duration.ofSeconds(1));
}
@Test
void mouseWheelMoveActive() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
Flux<ListViewSelectedItemChangedEvent<String>> actions = eventLoop
.viewEvents(LISTVIEW_STRING_TYPEREF);
StepVerifier verifier = StepVerifier.create(actions)
.expectNextCount(1)
.thenCancel()
.verifyLater();
MouseEvent eventDown = mouseWheelDown(0, 0);
MouseHandlerResult result = view.getMouseHandler().handle(MouseHandler.argsOf(eventDown));
assertThat(result).isNotNull().satisfies(r -> {
assertThat(r.event()).isEqualTo(eventDown);
assertThat(r.capture()).isEqualTo(view);
});
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
verifier.verify(Duration.ofSeconds(1));
}
@Test
void mouseClickMoveActive() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
Flux<ListViewSelectedItemChangedEvent<String>> actions = eventLoop
.viewEvents(LISTVIEW_STRING_TYPEREF);
StepVerifier verifier = StepVerifier.create(actions)
.expectNextCount(1)
.thenCancel()
.verifyLater();
MouseEvent event01 = mouseClick(0, 1);
view.getMouseHandler().handle(MouseHandler.argsOf(event01));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
verifier.verify(Duration.ofSeconds(1));
}
}
@Test
void arrowKeysMoveSelection() {
ListView<String> view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
assertThat(ReflectionTestUtils.getField(view, "selected")).isEqualTo(-1);
@Nested
class Navigation {
KeyEvent eventDown = KeyEvent.of(Key.CursorDown);
KeyEvent eventUp = KeyEvent.of(Key.CursorUp);
KeyHandlerResult result = view.getKeyHandler().handle(KeyHandler.argsOf(eventDown));
assertThat(result).isNotNull().satisfies(r -> {
assertThat(r.event()).isEqualTo(eventDown);
assertThat(r.consumed()).isTrue();
// assertThat(r.focus()).isEqualTo(view);
// assertThat(r.capture()).isEqualTo(view);
});
assertThat(selected(view)).isEqualTo(0);
result = view.getKeyHandler().handle(KeyHandler.argsOf(eventDown));
assertThat(selected(view)).isEqualTo(1);
result = view.getKeyHandler().handle(KeyHandler.argsOf(eventUp));
assertThat(selected(view)).isEqualTo(0);
}
@Test
void initialActiveIndexZeroWhenItemsSet() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.setItems(Arrays.asList("item1", "item2"));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
}
@Test
void mouseWheelMoveSelection() {
ListView<String> view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
assertThat(selected(view)).isEqualTo(-1);
@Test
void arrowMovesActiveFromFirstToLast() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
MouseEvent eventDown = mouseWheelDown(0, 0);
MouseEvent eventUp = mouseWheelUp(0, 0);
MouseHandlerResult result = view.getMouseHandler().handle(MouseHandler.argsOf(eventDown));
assertThat(result).isNotNull().satisfies(r -> {
assertThat(r.event()).isEqualTo(eventDown);
// assertThat(r.consumed()).isFalse();
// assertThat(r.focus()).isNull();
assertThat(r.capture()).isEqualTo(view);
});
assertThat(selected(view)).isEqualTo(0);
result = view.getMouseHandler().handle(MouseHandler.argsOf(eventDown));
assertThat(selected(view)).isEqualTo(1);
result = view.getMouseHandler().handle(MouseHandler.argsOf(eventUp));
assertThat(selected(view)).isEqualTo(0);
}
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.CursorUp)));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
}
@Test
void mouseClickMoveSelection() {
ListView<String> view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
assertThat(selected(view)).isEqualTo(-1);
@Test
void arrowMovesActiveFromLastToFirst() {
view = new ListView<>();
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
MouseEvent event00 = mouseClick(0, 0);
MouseEvent event01 = mouseClick(0, 1);
view.getMouseHandler().handle(MouseHandler.argsOf(event00));
assertThat(selected(view)).isEqualTo(0);
view.getMouseHandler().handle(MouseHandler.argsOf(event01));
assertThat(selected(view)).isEqualTo(1);
}
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.CursorDown)));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.CursorDown)));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
}
static int selected(ListView<?> view) {
return (int) ReflectionTestUtils.getField(view, "selected");
}
@Nested
class Visual {
@Test
void customCellFactory() {
ListView<String> view = new ListView<>();
void hasBorder() {
view = new ListView<>();
view.setShowBorder(true);
view.setCellFactory(list -> new TestListCell());
view.setRect(0, 0, 80, 24);
view.draw(screen24x80);
assertThat(forScreen(screen24x80)).hasBorder(0, 0, 80, 24);
}
@Test
void showingAllCells() {
view = new ListView<>();
view.setShowBorder(true);
view.setRect(0, 0, 10, 7);
view.setItems(Arrays.asList("item1", "item2", "item3"));
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
}
@Test
void showingCellsWhichFitVertically() {
view = new ListView<>();
view.setShowBorder(true);
view.setRect(0, 0, 10, 7);
view.setItems(Arrays.asList("item1", "item2", "item3", "item4", "item5", "item6", "item7"));
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
assertThat(forScreen(screen7x10)).hasNoHorizontalText("item6", 1, 6, 5);
}
@Test
void scrollUpThrough() {
view = new ListView<>();
view.setShowBorder(true);
view.setRect(0, 0, 10, 7);
view.setItems(Arrays.asList("item1", "item2", "item3", "item4", "item5", "item6", "item7"));
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(4);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(3);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(2);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(1);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, -1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
}
@Test
void scrollDownThrough() {
view = new ListView<>();
view.setShowBorder(true);
view.setRect(0, 0, 10, 7);
view.setItems(Arrays.asList("item1", "item2", "item3", "item4", "item5", "item6", "item7"));
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(1);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(2);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(3);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(4);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(1);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(4);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(2);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(4);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item6", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item7", 1, 5, 5);
clearScreens();
callVoidIntMethod(view, SCROLL_METHOD, 1);
assertThat(getIntField(view, START_FIELD)).isEqualTo(0);
assertThat(getIntField(view, POSITION_FIELD)).isEqualTo(0);
view.draw(screen7x10);
assertThat(forScreen(screen7x10)).hasHorizontalText("item1", 1, 1, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item2", 1, 2, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item3", 1, 3, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item4", 1, 4, 5);
assertThat(forScreen(screen7x10)).hasHorizontalText("item5", 1, 5, 5);
clearScreens();
}
}
@Nested
class Radio {
@Test
void showRadio() {
view = new ListView<>(ItemStyle.RADIO);
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.Space)));
assertThat(getIntSetField(view, SELECTED_FIELD)).containsExactly(0);
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.CursorDown)));
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.Space)));
assertThat(getIntSetField(view, SELECTED_FIELD)).containsExactly(1);
}
}
@Nested
class Checked {
@Test
void showChecked() {
view = new ListView<>(ItemStyle.CHECKED);
configure(view);
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1", "item2"));
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.Space)));
assertThat(getIntSetField(view, SELECTED_FIELD)).containsExactly(0);
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.CursorDown)));
view.getKeyHandler().handle(KeyHandler.argsOf(KeyEvent.of(Key.Space)));
assertThat(getIntSetField(view, SELECTED_FIELD)).containsExactly(0, 1);
}
}
@Nested
class Factory {
@Test
void customCellFactory() {
view = new ListView<>();
view.setShowBorder(true);
view.setCellFactory((list, item) -> new TestListCell(item));
view.setRect(0, 0, 80, 24);
view.setItems(Arrays.asList("item1"));
view.draw(screen24x80);
assertThat(forScreen(screen24x80)).hasHorizontalText("pre-item1-post", 0, 1, 16);
}
static class TestListCell extends ListCell<String> {
static class TestListCell extends AbstractListCell<String> {
TestListCell(String item) {
super(item);
}
@Override
public void draw(Screen screen) {

View File

@@ -18,6 +18,7 @@ package org.springframework.shell.component.view.control.cell;
import org.junit.jupiter.api.Test;
import org.springframework.shell.component.view.control.AbstractViewTests;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
import org.springframework.shell.component.view.screen.Color;
import org.springframework.shell.component.view.screen.ScreenItem;
@@ -26,40 +27,49 @@ import static org.assertj.core.api.Assertions.assertThat;
class ListCellTests extends AbstractViewTests {
@Test
void simpleTextWrites() {
ListCell<String> cell = new ListCell<>();
void simpleTextWritesNoCheck() {
ListCell<String> cell = ListCell.of("item", ItemStyle.NOCHECK);
cell.setRect(0, 0, 10, 1);
cell.updateItem("item");
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("item", 0, 0, 4);
}
@Test
void hasBackgroundColor() {
ListCell<String> cell = new ListCell<>();
cell.setBackgroundColor(Color.BLUE);
void simpleTextWritesChecked() {
ListCell<String> cell = ListCell.of("item", ItemStyle.CHECKED);
cell.setRect(0, 0, 10, 1);
cell.updateItem("item");
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("item", 0, 0, 4).hasBackgroundColor(0, 0, Color.BLUE);
assertThat(forScreen(screen10x10)).hasHorizontalText("[ ] item", 0, 0, 8);
cell.setSelected(true);
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("[x] item", 0, 0, 8);
}
@Test
void hasBackgroundColor() {
ListCell<String> cell = ListCell.of("item", ItemStyle.RADIO);
cell.setRect(0, 0, 10, 1);
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("[ ] item", 0, 0, 8);
cell.setSelected(true);
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("[x] item", 0, 0, 8);
}
@Test
void hasForegroundColor() {
ListCell<String> cell = new ListCell<>();
ListCell<String> cell = ListCell.of("item", ItemStyle.NOCHECK);
cell.setForegroundColor(Color.BLUE);
cell.setRect(0, 0, 10, 1);
cell.updateItem("item");
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("item", 0, 0, 4).hasForegroundColor(0, 0, Color.BLUE);
}
@Test
void hasStyle() {
ListCell<String> cell = new ListCell<>();
ListCell<String> cell = ListCell.of("item", ItemStyle.NOCHECK);
cell.setStyle(ScreenItem.STYLE_BOLD);
cell.setRect(0, 0, 10, 1);
cell.updateItem("item");
cell.draw(screen10x10);
assertThat(forScreen(screen10x10)).hasHorizontalText("item", 0, 0, 4).hasStyle(0, 0, ScreenItem.STYLE_BOLD);
}

View File

@@ -44,7 +44,7 @@ import org.springframework.shell.component.view.control.MenuView.MenuItemCheckSt
import org.springframework.shell.component.view.control.StatusBarView;
import org.springframework.shell.component.view.control.StatusBarView.StatusItem;
import org.springframework.shell.component.view.control.View;
import org.springframework.shell.component.view.control.cell.ListCell;
import org.springframework.shell.component.view.control.cell.AbstractListCell;
import org.springframework.shell.component.view.event.EventLoop;
import org.springframework.shell.component.view.event.KeyEvent;
import org.springframework.shell.component.view.event.KeyEvent.Key;
@@ -148,7 +148,7 @@ public class Catalog {
// start main scenario browser
ui.setRoot(app, true);
ui.setFocus(categories);
categories.setSelected(0);
// categories.setSelected(0);
ui.run();
}
@@ -238,7 +238,11 @@ public class Catalog {
return categories;
}
private static class ScenarioListCell extends ListCell<ScenarioData> {
private static class ScenarioListCell extends AbstractListCell<ScenarioData> {
public ScenarioListCell(ScenarioData item) {
super(item);
}
@Override
public void draw(Screen screen) {
@@ -257,7 +261,7 @@ public class Catalog {
scenarios.setTitle("Scenarios");
scenarios.setFocusedTitleStyle(ScreenItem.STYLE_BOLD);
scenarios.setShowBorder(true);
scenarios.setCellFactory(list -> new ScenarioListCell());
scenarios.setCellFactory((list, item) -> new ScenarioListCell(item));
return scenarios;
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.samples.catalog.scenario.listview;
import java.util.Arrays;
import org.springframework.shell.component.view.control.ListView;
import org.springframework.shell.component.view.control.View;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
import org.springframework.shell.samples.catalog.scenario.AbstractScenario;
import org.springframework.shell.samples.catalog.scenario.Scenario;
import org.springframework.shell.samples.catalog.scenario.ScenarioComponent;
@ScenarioComponent(name = "Radio List", description = "Items with radio states", category = { Scenario.CATEGORY_LISTVIEW })
public class CheckedListViewScenario extends AbstractScenario {
@Override
public View build() {
ListView<String> view = new ListView<>(ItemStyle.RADIO);
view.setEventLoop(getEventloop());
view.setItems(Arrays.asList("item1", "item2", "item3"));
return view;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.samples.catalog.scenario.listview;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.springframework.shell.component.view.control.ListView;
import org.springframework.shell.component.view.control.View;
import org.springframework.shell.samples.catalog.scenario.AbstractScenario;
import org.springframework.shell.samples.catalog.scenario.Scenario;
import org.springframework.shell.samples.catalog.scenario.ScenarioComponent;
@ScenarioComponent(name = "Long List", description = "Show many items", category = { Scenario.CATEGORY_LISTVIEW })
public class LongListViewScenario extends AbstractScenario {
@Override
public View build() {
ListView<String> view = new ListView<>();
view.setEventLoop(getEventloop());
List<String> items = IntStream.of(20).mapToObj(i -> "item" + i).collect(Collectors.toList());
view.setItems(items);
return view;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.shell.samples.catalog.scenario.listview;
import java.util.Arrays;
import org.springframework.shell.component.view.control.ListView;
import org.springframework.shell.component.view.control.View;
import org.springframework.shell.component.view.control.ListView.ItemStyle;
import org.springframework.shell.samples.catalog.scenario.AbstractScenario;
import org.springframework.shell.samples.catalog.scenario.Scenario;
import org.springframework.shell.samples.catalog.scenario.ScenarioComponent;
@ScenarioComponent(name = "Checked List", description = "Items with checked states", category = { Scenario.CATEGORY_LISTVIEW })
public class RadioListViewScenario extends AbstractScenario {
@Override
public View build() {
ListView<String> view = new ListView<>(ItemStyle.CHECKED);
view.setEventLoop(getEventloop());
view.setItems(Arrays.asList("item1", "item2", "item3"));
return view;
}
}