Skip to content

Commit 2862cc8

Browse files
Drevshjvalkeal
authored andcommitted
Add default selection to MultiItemSelector
- Added default selection to items - Added correct styling for disabled but default selected item - Added missing license header - Added missing javadoc - Added default selection to sample/doc code
1 parent 329c7eb commit 2862cc8

File tree

12 files changed

+92
-24
lines changed

12 files changed

+92
-24
lines changed

spring-shell-core/src/main/java/org/springframework/shell/component/MultiItemSelector.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.shell.component.support.Itemable;
3333
import org.springframework.shell.component.support.Matchable;
3434
import org.springframework.shell.component.support.Nameable;
35+
import org.springframework.shell.component.support.Selectable;
3536
import org.springframework.shell.component.support.AbstractSelectorComponent.SelectorComponentContext;
3637
import org.springframework.shell.component.MultiItemSelector.MultiItemSelectorContext;
3738

@@ -40,7 +41,7 @@
4041
*
4142
* @author Janne Valkealahti
4243
*/
43-
public class MultiItemSelector<T, I extends Nameable & Matchable & Enableable & Itemable<T>>
44+
public class MultiItemSelector<T, I extends Nameable & Matchable & Enableable & Selectable & Itemable<T>>
4445
extends AbstractSelectorComponent<T, MultiItemSelectorContext<T, I>, I> {
4546

4647
private MultiItemSelectorContext<T, I> currentContext;

spring-shell-core/src/main/java/org/springframework/shell/component/SingleItemSelector.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
import org.springframework.shell.component.support.Itemable;
3333
import org.springframework.shell.component.support.Matchable;
3434
import org.springframework.shell.component.support.Nameable;
35+
import org.springframework.shell.component.support.Selectable;
3536
import org.springframework.shell.component.support.AbstractSelectorComponent.SelectorComponentContext;
3637
import org.springframework.shell.component.SingleItemSelector.SingleItemSelectorContext;
3738

@@ -40,7 +41,7 @@
4041
*
4142
* @author Janne Valkealahti
4243
*/
43-
public class SingleItemSelector<T, I extends Nameable & Matchable & Enableable & Itemable<T>>
44+
public class SingleItemSelector<T, I extends Nameable & Matchable & Enableable & Selectable & Itemable<T>>
4445
extends AbstractSelectorComponent<T, SingleItemSelectorContext<T, I>, I> {
4546

4647
private SingleItemSelectorContext<T, I> currentContext;

spring-shell-core/src/main/java/org/springframework/shell/component/flow/ComponentFlow.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -617,7 +617,7 @@ private Stream<OrderedInputOperation> singleItemSelectorsStream() {
617617
private Stream<OrderedInputOperation> multiItemSelectorsStream() {
618618
return multiInputs.stream().map(input -> {
619619
List<SelectorItem<String>> selectorItems = input.getSelectItems().stream()
620-
.map(si -> SelectorItem.of(si.name(), si.item(), si.enabled()))
620+
.map(si -> SelectorItem.of(si.name(), si.item(), si.enabled(), si.selected()))
621621
.collect(Collectors.toList());
622622
MultiItemSelector<String, SelectorItem<String>> selector = new MultiItemSelector<>(terminal,
623623
selectorItems, input.getName(), input.getComparator());

spring-shell-core/src/main/java/org/springframework/shell/component/flow/DefaultSelectItem.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@ public class DefaultSelectItem implements SelectItem {
2525
private String name;
2626
private String item;
2727
private boolean enabled;
28+
private boolean selected;
2829

29-
public DefaultSelectItem(String name, String item, boolean enabled) {
30+
public DefaultSelectItem(String name, String item, boolean enabled, boolean selected) {
3031
this.name = name;
3132
this.item = item;
3233
this.enabled = enabled;
34+
this.selected = selected;
3335
}
3436

3537
@Override
@@ -46,4 +48,9 @@ public String item() {
4648
public boolean enabled() {
4749
return enabled;
4850
}
51+
52+
@Override
53+
public boolean selected() {
54+
return selected;
55+
}
4956
}

spring-shell-core/src/main/java/org/springframework/shell/component/flow/SelectItem.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,18 @@ public interface SelectItem {
4343
*/
4444
boolean enabled();
4545

46+
/**
47+
* Return if the item is selected.
48+
*
49+
* @return if item is selected
50+
*/
51+
boolean selected();
52+
4653
public static SelectItem of(String name, String item) {
47-
return of(name, item, true);
54+
return of(name, item, true, false);
4855
}
4956

50-
public static SelectItem of(String name, String item, boolean enabled) {
51-
return new DefaultSelectItem(name, item, enabled);
57+
public static SelectItem of(String name, String item, boolean enabled, boolean selected) {
58+
return new DefaultSelectItem(name, item, enabled, selected);
5259
}
5360
}

spring-shell-core/src/main/java/org/springframework/shell/component/support/AbstractSelectorComponent.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
*
4646
* @author Janne Valkealahti
4747
*/
48-
public abstract class AbstractSelectorComponent<T, C extends SelectorComponentContext<T, I, C>, I extends Nameable & Matchable & Enableable & Itemable<T>>
48+
public abstract class AbstractSelectorComponent<T, C extends SelectorComponentContext<T, I, C>, I extends Nameable & Matchable & Enableable & Selectable & Itemable<T>>
4949
extends AbstractComponent<C> {
5050

5151
private final static Logger log = LoggerFactory.getLogger(AbstractSelectorComponent.class);
@@ -257,7 +257,7 @@ private void initialExpose(C context) {
257257
AtomicInteger index = new AtomicInteger(0);
258258
itemStates = context.getItems().stream()
259259
.sorted(comparator)
260-
.map(item -> ItemState.of(item, item.getName(), index.getAndIncrement(), item.isEnabled()))
260+
.map(item -> ItemState.of(item, item.getName(), index.getAndIncrement(), item.isEnabled(), item.isSelected()))
261261
.collect(Collectors.toList());
262262
}
263263
for (int i = 0; i < itemStates.size(); i++) {
@@ -280,7 +280,7 @@ private ItemStateViewProjection buildItemStateView(int skip, SelectorComponentCo
280280
AtomicInteger index = new AtomicInteger(0);
281281
itemStates = context.getItems().stream()
282282
.sorted(comparator)
283-
.map(item -> ItemState.of(item, item.getName(), index.getAndIncrement(), item.isEnabled()))
283+
.map(item -> ItemState.of(item, item.getName(), index.getAndIncrement(), item.isEnabled(), item.isSelected()))
284284
.collect(Collectors.toList());
285285
context.setItemStates(itemStates);
286286
}
@@ -547,11 +547,12 @@ public static class ItemState<I extends Matchable> implements Matchable {
547547
boolean enabled;
548548
int index;
549549

550-
ItemState(I item, String name, int index, boolean enabled) {
550+
ItemState(I item, String name, int index, boolean enabled, boolean selected) {
551551
this.item = item;
552552
this.name = name;
553553
this.index = index;
554554
this.enabled = enabled;
555+
this.selected = selected;
555556
}
556557

557558
public boolean matches(String match) {
@@ -574,8 +575,8 @@ public boolean isEnabled() {
574575
return enabled;
575576
}
576577

577-
static <I extends Matchable> ItemState<I> of(I item, String name, int index, boolean enabled) {
578-
return new ItemState<I>(item, name, index, enabled);
578+
static <I extends Matchable> ItemState<I> of(I item, String name, int index, boolean enabled, boolean selected) {
579+
return new ItemState<I>(item, name, index, enabled, selected);
579580
}
580581
}
581582

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.shell.component.support;
17+
18+
public interface Selectable {
19+
20+
boolean isSelected();
21+
}

spring-shell-core/src/main/java/org/springframework/shell/component/support/SelectorItem.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,31 @@
1717

1818
import org.springframework.util.StringUtils;
1919

20-
public interface SelectorItem<T> extends Nameable, Matchable, Enableable, Itemable<T> {
20+
public interface SelectorItem<T> extends Nameable, Matchable, Enableable, Selectable, Itemable<T> {
2121

2222
static <T> SelectorItem<T> of(String name, T item) {
23-
return of(name, item, true);
23+
return of(name, item, true, false);
2424
}
2525

26-
static <T> SelectorItem<T> of(String name, T item, boolean enabled) {
27-
return new SelectorItemWrapper<T>(name, item, enabled);
26+
static <T> SelectorItem<T> of(String name, T item, boolean enabled, boolean selected) {
27+
return new SelectorItemWrapper<T>(name, item, enabled, selected);
2828
}
2929

3030
public static class SelectorItemWrapper<T> implements SelectorItem<T> {
3131
private String name;
3232
private boolean enabled;
3333
private T item;
34+
private boolean selected;
3435

3536
public SelectorItemWrapper(String name, T item) {
36-
this(name, item, true);
37+
this(name, item, true, false);
3738
}
3839

39-
public SelectorItemWrapper(String name, T item, boolean enabled) {
40+
public SelectorItemWrapper(String name, T item, boolean enabled, boolean selected) {
4041
this.name = name;
4142
this.item = item;
4243
this.enabled = enabled;
44+
this.selected = selected;
4345
}
4446

4547
@Override
@@ -51,7 +53,7 @@ public String getName() {
5153
public boolean matches(String match) {
5254
if (!StringUtils.hasText(match)) {
5355
return true;
54-
};
56+
}
5557
return name.toLowerCase().contains(match.toLowerCase());
5658
}
5759

@@ -60,8 +62,14 @@ public boolean isEnabled() {
6062
return enabled;
6163
}
6264

65+
@Override
6366
public T getItem() {
6467
return item;
6568
}
69+
70+
@Override
71+
public boolean isSelected() {
72+
return selected;
73+
}
6674
}
6775
}

spring-shell-core/src/main/resources/org/springframework/shell/component/multi-item-selector-default.stg

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,11 @@ select_item(item) ::= <%
1818
<({<figures.checkboxOff> }); format=selected_style(item.selected)> <item.name>
1919
<endif>
2020
<else>
21-
<({<figures.checkboxOff> }); format="style-item-disabled"> <item.name; format="style-item-disabled">
21+
<if(item.selected)>
22+
<({<figures.checkboxOn> }); format="style-item-disabled"> <item.name; format="style-item-disabled">
23+
<else>
24+
<({<figures.checkboxOff> }); format="style-item-disabled"> <item.name; format="style-item-disabled">
25+
<endif>
2226
<endif>
2327
%>
2428

spring-shell-core/src/test/java/org/springframework/shell/component/MultiItemSelectorTests.java

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,15 @@ public class MultiItemSelectorTests extends AbstractShellTests {
5151
private static SimplePojo SIMPLE_POJO_5 = SimplePojo.of("data5");
5252
private static SimplePojo SIMPLE_POJO_6 = SimplePojo.of("data6");
5353
private static SimplePojo SIMPLE_POJO_7 = SimplePojo.of("data7");
54+
private static SimplePojo SIMPLE_POJO_8 = SimplePojo.of("data8");
5455
private static SelectorItem<SimplePojo> SELECTOR_ITEM_1 = SelectorItem.of("simplePojo1", SIMPLE_POJO_1);
5556
private static SelectorItem<SimplePojo> SELECTOR_ITEM_2 = SelectorItem.of("simplePojo2", SIMPLE_POJO_2);
5657
private static SelectorItem<SimplePojo> SELECTOR_ITEM_3 = SelectorItem.of("simplePojo3", SIMPLE_POJO_3);
5758
private static SelectorItem<SimplePojo> SELECTOR_ITEM_4 = SelectorItem.of("simplePojo4", SIMPLE_POJO_4);
5859
private static SelectorItem<SimplePojo> SELECTOR_ITEM_5 = SelectorItem.of("simplePojo5", SIMPLE_POJO_5);
5960
private static SelectorItem<SimplePojo> SELECTOR_ITEM_6 = SelectorItem.of("simplePojo6", SIMPLE_POJO_6);
60-
private static SelectorItem<SimplePojo> SELECTOR_ITEM_7 = SelectorItem.of("simplePojo7", SIMPLE_POJO_7, false);
61+
private static SelectorItem<SimplePojo> SELECTOR_ITEM_7 = SelectorItem.of("simplePojo7", SIMPLE_POJO_7, false, false);
62+
private static SelectorItem<SimplePojo> SELECTOR_ITEM_8 = SelectorItem.of("simplePojo8", SIMPLE_POJO_8, false, true);
6163

6264
private ExecutorService service;
6365
private CountDownLatch latch;
@@ -204,6 +206,22 @@ public void testSelectLastBackwards() throws InterruptedException {
204206
Stream<String> datas = selected.stream().map(SelectorItem::getItem).map(SimplePojo::getData);
205207
assertThat(datas).containsExactlyInAnyOrder("data4");
206208
}
209+
210+
@Test
211+
public void testDefaultSelection() throws InterruptedException {
212+
scheduleSelect(Arrays.asList(SELECTOR_ITEM_1, SELECTOR_ITEM_2, SELECTOR_ITEM_7, SELECTOR_ITEM_8));
213+
214+
TestBuffer testBuffer = new TestBuffer().cr();
215+
write(testBuffer.getBytes());
216+
217+
awaitLatch();
218+
219+
List<SelectorItem<SimplePojo>> selected = result.get();
220+
assertThat(selected).hasSize(1);
221+
Stream<String> datas = selected.stream().map(SelectorItem::getItem).map(SimplePojo::getData);
222+
assertThat(datas).containsExactlyInAnyOrder("data8");
223+
assertThat(consoleOut()).contains("testSimple data8");
224+
}
207225

208226
private void scheduleSelect() {
209227
scheduleSelect(Arrays.asList(SELECTOR_ITEM_1, SELECTOR_ITEM_2, SELECTOR_ITEM_3,

spring-shell-docs/src/test/java/org/springframework/shell/docs/UiComponentSnippets.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ public class ComponentCommands extends AbstractShellComponent {
170170
public String multiSelector() {
171171
List<SelectorItem<String>> items = new ArrayList<>();
172172
items.add(SelectorItem.of("key1", "value1"));
173-
items.add(SelectorItem.of("key2", "value2", false));
173+
items.add(SelectorItem.of("key2", "value2", false, true));
174174
items.add(SelectorItem.of("key3", "value3"));
175175
MultiItemSelector<String, SelectorItem<String>> component = new MultiItemSelector<>(getTerminal(),
176176
items, "testSimple", null);

spring-shell-samples/src/main/java/org/springframework/shell/samples/standard/ComponentCommands.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public String singleSelector() {
9393
public String multiSelector() {
9494
List<SelectorItem<String>> items = new ArrayList<>();
9595
items.add(SelectorItem.of("key1", "value1"));
96-
items.add(SelectorItem.of("key2", "value2", false));
96+
items.add(SelectorItem.of("key2", "value2", false, true));
9797
items.add(SelectorItem.of("key3", "value3"));
9898
MultiItemSelector<String, SelectorItem<String>> component = new MultiItemSelector<>(getTerminal(),
9999
items, "testSimple", null);

0 commit comments

Comments
 (0)