Aditionnal methods in DisplayUtil + some refactoring
This commit is contained in:
parent
e65c402684
commit
34e015cb01
@ -1,60 +0,0 @@
|
||||
package fr.pandacube.util;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DateUtil {
|
||||
|
||||
/**
|
||||
* @see {@link com.earth2me.essentials.utils.DateUtil#parseDateDiff(String, boolean)}
|
||||
*/
|
||||
public static long parseDateDiff(String time, boolean future) throws Exception {
|
||||
Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = timePattern.matcher(time);
|
||||
int years = 0;
|
||||
int months = 0;
|
||||
int weeks = 0;
|
||||
int days = 0;
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
int seconds = 0;
|
||||
boolean found = false;
|
||||
while (m.find()) {
|
||||
if (m.group() == null || m.group().isEmpty()) continue;
|
||||
for (int i = 0; i < m.groupCount(); i++)
|
||||
if (m.group(i) != null && !m.group(i).isEmpty()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
if (m.group(1) != null && !m.group(1).isEmpty()) years = Integer.parseInt(m.group(1));
|
||||
if (m.group(2) != null && !m.group(2).isEmpty()) months = Integer.parseInt(m.group(2));
|
||||
if (m.group(3) != null && !m.group(3).isEmpty()) weeks = Integer.parseInt(m.group(3));
|
||||
if (m.group(4) != null && !m.group(4).isEmpty()) days = Integer.parseInt(m.group(4));
|
||||
if (m.group(5) != null && !m.group(5).isEmpty()) hours = Integer.parseInt(m.group(5));
|
||||
if (m.group(6) != null && !m.group(6).isEmpty()) minutes = Integer.parseInt(m.group(6));
|
||||
if (m.group(7) != null && !m.group(7).isEmpty()) seconds = Integer.parseInt(m.group(7));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) throw new Exception("Format de durée invalide");
|
||||
Calendar c = new GregorianCalendar();
|
||||
if (years > 0) c.add(Calendar.YEAR, years * (future ? 1 : -1));
|
||||
if (months > 0) c.add(Calendar.MONTH, months * (future ? 1 : -1));
|
||||
if (weeks > 0) c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1));
|
||||
if (days > 0) c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1));
|
||||
if (hours > 0) c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1));
|
||||
if (minutes > 0) c.add(Calendar.MINUTE, minutes * (future ? 1 : -1));
|
||||
if (seconds > 0) c.add(Calendar.SECOND, seconds * (future ? 1 : -1));
|
||||
Calendar max = new GregorianCalendar();
|
||||
max.add(Calendar.YEAR, 10);
|
||||
if (c.after(max)) return max.getTimeInMillis();
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
}
|
@ -3,11 +3,13 @@ package fr.pandacube.util;
|
||||
import java.io.File;
|
||||
|
||||
public class DirUtils {
|
||||
|
||||
|
||||
|
||||
public static void delete(final File target) {
|
||||
if (target.isDirectory())
|
||||
for (final File child : target.listFiles())
|
||||
for (File child : target.listFiles())
|
||||
delete(child);
|
||||
|
||||
target.delete();
|
||||
}
|
||||
}
|
||||
|
@ -12,10 +12,10 @@ import java.util.stream.Stream;
|
||||
import fr.pandacube.util.ListUtil;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface Suggestions<S> {
|
||||
public interface SuggestionsSupplier<S> {
|
||||
|
||||
/**
|
||||
* Number of suggestion visible at once without having to scrolleeeeeeeeeeeeeeee
|
||||
* Number of suggestion visible at once without having to scroll
|
||||
*/
|
||||
public static int VISIBLE_SUGGESTION_COUNT = 10;
|
||||
|
||||
@ -45,33 +45,33 @@ public interface Suggestions<S> {
|
||||
|
||||
|
||||
|
||||
public static <S> Suggestions<S> empty() { return (s, ti, t, a) -> Collections.emptyList(); }
|
||||
public static <S> SuggestionsSupplier<S> empty() { return (s, ti, t, a) -> Collections.emptyList(); }
|
||||
|
||||
|
||||
public static <S> Suggestions<S> fromCollection(Collection<String> suggestions) {
|
||||
public static <S> SuggestionsSupplier<S> fromCollection(Collection<String> suggestions) {
|
||||
return (s, ti, token, a) -> collectFilteredStream(suggestions.stream(), token);
|
||||
}
|
||||
|
||||
public static <S> Suggestions<S> fromArray(String... suggestions) {
|
||||
public static <S> SuggestionsSupplier<S> fromArray(String... suggestions) {
|
||||
return (s, ti, token, a) -> collectFilteredStream(Arrays.stream(suggestions), token);
|
||||
}
|
||||
|
||||
|
||||
public static <E extends Enum<E>, S> Suggestions<S> fromEnum(Class<E> enumClass) {
|
||||
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass) {
|
||||
return fromEnumValues(enumClass.getEnumConstants());
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>, S> Suggestions<S> fromEnum(Class<E> enumClass, boolean lowerCase) {
|
||||
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnum(Class<E> enumClass, boolean lowerCase) {
|
||||
return fromEnumValues(lowerCase, enumClass.getEnumConstants());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <E extends Enum<E>, S> Suggestions<S> fromEnumValues(E... enumValues) {
|
||||
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(E... enumValues) {
|
||||
return fromEnumValues(false, enumValues);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <E extends Enum<E>, S> Suggestions<S> fromEnumValues(boolean lowerCase, E... enumValues) {
|
||||
public static <E extends Enum<E>, S> SuggestionsSupplier<S> fromEnumValues(boolean lowerCase, E... enumValues) {
|
||||
return (s, ti, token, a) -> {
|
||||
Stream<String> st = Arrays.stream(enumValues).map(Enum::name);
|
||||
if (lowerCase)
|
||||
@ -82,14 +82,14 @@ public interface Suggestions<S> {
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link Suggestions} that suggest numbers according to the provided range.
|
||||
* Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range.
|
||||
*
|
||||
* The current implementation only support range that include either -1 or 1.
|
||||
* @param min
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public static <S> Suggestions<S> fromIntRange(int min, int max) {
|
||||
public static <S> SuggestionsSupplier<S> fromIntRange(int min, int max) {
|
||||
return fromLongRange(min, max);
|
||||
}
|
||||
|
||||
@ -97,14 +97,14 @@ public interface Suggestions<S> {
|
||||
|
||||
|
||||
/**
|
||||
* Create a {@link Suggestions} that suggest numbers according to the provided range.
|
||||
* Create a {@link SuggestionsSupplier} that suggest numbers according to the provided range.
|
||||
*
|
||||
* The current implementation only support range that include either -1 or 1.
|
||||
* @param min
|
||||
* @param max
|
||||
* @return
|
||||
*/
|
||||
public static <S> Suggestions<S> fromLongRange(long min, long max) {
|
||||
public static <S> SuggestionsSupplier<S> fromLongRange(long min, long max) {
|
||||
if (max < min) {
|
||||
throw new IllegalArgumentException("min should be less or equals than max");
|
||||
}
|
||||
@ -168,12 +168,12 @@ public interface Suggestions<S> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link Suggestions} that support greedy strings argument using the suggestion from this {@link Suggestions}.
|
||||
* Create a {@link SuggestionsSupplier} that support greedy strings argument using the suggestion from this {@link SuggestionsSupplier}.
|
||||
* @param args all the arguments currently in the buffer
|
||||
* @param index the index of the first argument of the greedy string argument
|
||||
* @return
|
||||
*/
|
||||
public default Suggestions<S> greedyString(int index) {
|
||||
public default SuggestionsSupplier<S> greedyString(int index) {
|
||||
|
||||
return (s, ti, token, args) -> {
|
||||
|
||||
@ -206,7 +206,7 @@ public interface Suggestions<S> {
|
||||
|
||||
|
||||
|
||||
public default Suggestions<S> requires(Predicate<S> check) {
|
||||
public default SuggestionsSupplier<S> requires(Predicate<S> check) {
|
||||
return (s, ti, to, a) -> {
|
||||
return check.test(s) ? getSuggestions(s, ti, to, a) : Collections.emptyList();
|
||||
};
|
@ -1,5 +1,10 @@
|
||||
package fr.pandacube.util.measurement;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class TimeUtil {
|
||||
public static String durationToString(long msec_time, boolean dec_seconde) {
|
||||
boolean neg = msec_time < 0;
|
||||
@ -37,5 +42,57 @@ public class TimeUtil {
|
||||
public static String durationToString(long msec_time) {
|
||||
return durationToString(msec_time, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see {@link com.earth2me.essentials.utils.DateUtil#parseDateDiff(String, boolean)}
|
||||
*/
|
||||
public static long parseDateDiff(String time, boolean future) throws Exception {
|
||||
Pattern timePattern = Pattern.compile("(?:([0-9]+)\\s*y[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*mo[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*w[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*d[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*h[a-z]*[,\\s]*)?" + "(?:([0-9]+)\\s*m[a-z]*[,\\s]*)?"
|
||||
+ "(?:([0-9]+)\\s*(?:s[a-z]*)?)?", Pattern.CASE_INSENSITIVE);
|
||||
Matcher m = timePattern.matcher(time);
|
||||
int years = 0;
|
||||
int months = 0;
|
||||
int weeks = 0;
|
||||
int days = 0;
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
int seconds = 0;
|
||||
boolean found = false;
|
||||
while (m.find()) {
|
||||
if (m.group() == null || m.group().isEmpty()) continue;
|
||||
for (int i = 0; i < m.groupCount(); i++)
|
||||
if (m.group(i) != null && !m.group(i).isEmpty()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
if (found) {
|
||||
if (m.group(1) != null && !m.group(1).isEmpty()) years = Integer.parseInt(m.group(1));
|
||||
if (m.group(2) != null && !m.group(2).isEmpty()) months = Integer.parseInt(m.group(2));
|
||||
if (m.group(3) != null && !m.group(3).isEmpty()) weeks = Integer.parseInt(m.group(3));
|
||||
if (m.group(4) != null && !m.group(4).isEmpty()) days = Integer.parseInt(m.group(4));
|
||||
if (m.group(5) != null && !m.group(5).isEmpty()) hours = Integer.parseInt(m.group(5));
|
||||
if (m.group(6) != null && !m.group(6).isEmpty()) minutes = Integer.parseInt(m.group(6));
|
||||
if (m.group(7) != null && !m.group(7).isEmpty()) seconds = Integer.parseInt(m.group(7));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) throw new Exception("Format de durée invalide");
|
||||
Calendar c = new GregorianCalendar();
|
||||
if (years > 0) c.add(Calendar.YEAR, years * (future ? 1 : -1));
|
||||
if (months > 0) c.add(Calendar.MONTH, months * (future ? 1 : -1));
|
||||
if (weeks > 0) c.add(Calendar.WEEK_OF_YEAR, weeks * (future ? 1 : -1));
|
||||
if (days > 0) c.add(Calendar.DAY_OF_MONTH, days * (future ? 1 : -1));
|
||||
if (hours > 0) c.add(Calendar.HOUR_OF_DAY, hours * (future ? 1 : -1));
|
||||
if (minutes > 0) c.add(Calendar.MINUTE, minutes * (future ? 1 : -1));
|
||||
if (seconds > 0) c.add(Calendar.SECOND, seconds * (future ? 1 : -1));
|
||||
Calendar max = new GregorianCalendar();
|
||||
max.add(Calendar.YEAR, 10);
|
||||
if (c.after(max)) return max.getTimeInMillis();
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -108,6 +108,9 @@ public class Display {
|
||||
* @return this
|
||||
*/
|
||||
public Display next(BaseComponent[] components) {
|
||||
if (components != null && components.length == 1)
|
||||
return next(components[0]);
|
||||
|
||||
BaseComponent bc = new TextComponent();
|
||||
for (BaseComponent c : components)
|
||||
bc.addExtra(c);
|
||||
@ -256,6 +259,16 @@ public class Display {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the player to click on the current component to copy content to the clipboard.
|
||||
* @param str the string to copy to clipboard
|
||||
* @return this
|
||||
*/
|
||||
public Display clickClipboard(String str) {
|
||||
current.setClickEvent(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, str));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow the player to click on the current component to run the specified command.
|
||||
* This method is only relevant if this Display is intended to be displayed in the chat, in a book or on a sign.
|
||||
@ -301,6 +314,8 @@ public class Display {
|
||||
*/
|
||||
public BaseComponent get() {
|
||||
finalizeCurrentComponent();
|
||||
if (!root.hasFormatting() && root.getExtra() != null && root.getExtra().size() == 1)
|
||||
return root.getExtra().get(0);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
@ -17,11 +19,12 @@ public class DisplayUtil {
|
||||
public static final int DEFAULT_CHAR_SIZE = 6;
|
||||
public static final Map<Integer, String> CHARS_SIZE = new ImmutableMap.Builder<Integer, String>()
|
||||
.put(-6, "§")
|
||||
.put(2, "!.,:;i|¡")
|
||||
.put(3, "'`lìí")
|
||||
.put(2, "!.,:;i|¡'")
|
||||
.put(3, "`lìí’‘")
|
||||
.put(4, " I[]tï×")
|
||||
.put(5, "\"()*<>fk{}")
|
||||
.put(7, "@~®")
|
||||
.put(7, "@~®©«»")
|
||||
.put(9, "├└")
|
||||
.build();
|
||||
|
||||
|
||||
@ -115,6 +118,63 @@ public class DisplayUtil {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @param cmdFormat the command with %d inside to be replaced with the page number (must start with slash)
|
||||
*/
|
||||
public static BaseComponent createPagination(String prefix, String cmdFormat, int currentPage, int nbPages, int nbPagesToDisplay) {
|
||||
Set<Integer> pagesToDisplay = new TreeSet<>();
|
||||
|
||||
for (int i = 0; i < nbPagesToDisplay && i < nbPages && nbPages - i > 0; i++) {
|
||||
pagesToDisplay.add(i + 1);
|
||||
pagesToDisplay.add(nbPages - i);
|
||||
}
|
||||
|
||||
for (int i = currentPage - nbPagesToDisplay + 1; i < currentPage + nbPagesToDisplay; i++) {
|
||||
if (i > 0 && i <= nbPages)
|
||||
pagesToDisplay.add(i);
|
||||
}
|
||||
|
||||
Display d = new Display(prefix);
|
||||
boolean first = true;
|
||||
int previous = 0;
|
||||
|
||||
for (int page : pagesToDisplay) {
|
||||
if (!first) {
|
||||
if (page == previous + 1) {
|
||||
d.next(" ");
|
||||
}
|
||||
else {
|
||||
if (cmdFormat.endsWith("%d")) {
|
||||
d.next(" ");
|
||||
d.next(createCommandSuggest("...", cmdFormat.substring(0, cmdFormat.length() - 2), "Choisir la page"));
|
||||
d.next(" ");
|
||||
}
|
||||
else
|
||||
d.next(" ... ");
|
||||
}
|
||||
}
|
||||
else
|
||||
first = false;
|
||||
|
||||
d.next(createCommandLink(Integer.toString(page), String.format(cmdFormat, page), "Aller à la page " + page));
|
||||
if (page == currentPage) {
|
||||
d.color(ChatColor.WHITE);
|
||||
}
|
||||
|
||||
previous = page;
|
||||
}
|
||||
|
||||
|
||||
return d.get();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// TODO refaire les 4 methodes ci-dessous
|
||||
|
||||
|
||||
@ -416,5 +476,152 @@ public class DisplayUtil {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Force a text to be italic, while keeping other formatting and colors.
|
||||
* The text is prefixed with the ITALIC tag, but is not reset at the end.
|
||||
* @param legacyText the original text
|
||||
* @return the text fully italic
|
||||
*/
|
||||
public static String forceItalic(String legacyText) {
|
||||
return forceFormat(legacyText, ChatColor.ITALIC);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a text to be bold, while keeping other formatting and colors.
|
||||
* The text is prefixed with the BOLD tag, but is not reset at the end.
|
||||
* @param legacyText the original text
|
||||
* @return the text fully bold
|
||||
*/
|
||||
public static String forceBold(String legacyText) {
|
||||
return forceFormat(legacyText, ChatColor.BOLD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a text to be underlined, while keeping other formatting and colors.
|
||||
* The text is prefixed with the UNDERLINE tag, but is not reset at the end.
|
||||
* @param legacyText the original text
|
||||
* @return the text fully underlined
|
||||
*/
|
||||
public static String forceUnderline(String legacyText) {
|
||||
return forceFormat(legacyText, ChatColor.UNDERLINE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a text to be stroked through, while keeping other formatting and colors.
|
||||
* The text is prefixed with the STRIKETHROUGH tag, but is not reset at the end.
|
||||
* @param legacyText the original text
|
||||
* @return the text fully stroked through
|
||||
*/
|
||||
public static String forceStrikethrough(String legacyText) {
|
||||
return forceFormat(legacyText, ChatColor.STRIKETHROUGH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force a text to be obfuscated, while keeping other formatting and colors.
|
||||
* The text is prefixed with the MAGIC tag, but is not reset at the end.
|
||||
* @param legacyText the original text
|
||||
* @return the text fully obfuscated
|
||||
*/
|
||||
public static String forceObfuscated(String legacyText) {
|
||||
return forceFormat(legacyText, ChatColor.MAGIC);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static String forceFormat(String legacyText, ChatColor format) {
|
||||
return format + legacyText
|
||||
.replace(format.toString(), "") // remove previous tag to make the result cleaner
|
||||
.replaceAll("§([a-frA-FR0-9])", "§$1" + format);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Replace the RESET tag of the input string to the specified color tag.
|
||||
* @param legacyText the original text
|
||||
* @param color the color to used to replace the RESET tag
|
||||
* (can be a combination of a color tag followed by multiple format tag)
|
||||
* @return the resulting text
|
||||
*/
|
||||
public static String resetToColor(String legacyText, String color) {
|
||||
return legacyText.replace(ChatColor.RESET.toString(), color);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Generate a tree view based on the tree structure {@code node}.
|
||||
*
|
||||
* Each element in the returned array represent 1 line of the tree view.
|
||||
* Thus, the caller may send each line separately or at once depending of the quantity of data.
|
||||
* @param node
|
||||
* @return A array of component, each element being a single line.
|
||||
*/
|
||||
public static BaseComponent[] treeView(DisplayTreeNode node, boolean console) {
|
||||
List<TextComponent> ret = treeView_(node, console);
|
||||
return ret.toArray(new BaseComponent[ret.size()]);
|
||||
}
|
||||
|
||||
private static final String TREE_MIDDLE_CONNECTED = "├";
|
||||
private static final String TREE_END_CONNECTED = "└";
|
||||
private static final String TREE_MIDDLE_OPEN = "│§0`§r";
|
||||
private static final String TREE_END_OPEN = "§0```§r";
|
||||
private static final String TREE_MIDDLE_OPEN_CONSOLE = "│";
|
||||
private static final String TREE_END_OPEN_CONSOLE = " "; // nbsp
|
||||
|
||||
private static List<TextComponent> treeView_(DisplayTreeNode node, boolean console) {
|
||||
List<TextComponent> ret = new ArrayList<>();
|
||||
|
||||
TextComponent curr = new TextComponent();
|
||||
curr.addExtra(node.component);
|
||||
curr.setText("");
|
||||
|
||||
ret.add(curr);
|
||||
|
||||
for (int i = 0; i < node.children.size(); i++) {
|
||||
List<TextComponent> childComponents = treeView_(node.children.get(i), console);
|
||||
boolean last = i == node.children.size() - 1;
|
||||
for (int j = 0; j < childComponents.size(); j++) {
|
||||
TextComponent cComp = childComponents.get(j);
|
||||
String prefix = last ? (j == 0 ? TREE_END_CONNECTED : (console ? TREE_END_OPEN_CONSOLE : TREE_END_OPEN))
|
||||
: (j == 0 ? TREE_MIDDLE_CONNECTED : (console ? TREE_MIDDLE_OPEN_CONSOLE : TREE_MIDDLE_OPEN));
|
||||
cComp.setText(prefix + cComp.getText());
|
||||
ret.add(cComp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class DisplayTreeNode {
|
||||
public final BaseComponent component;
|
||||
public final List<DisplayTreeNode> children = new ArrayList<>();
|
||||
|
||||
public DisplayTreeNode(BaseComponent cmp) {
|
||||
component = cmp;
|
||||
}
|
||||
|
||||
public DisplayTreeNode addChild(DisplayTreeNode child) {
|
||||
children.add(child);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user