From 0117159159ca269ca16590c61519c38339faaa72 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Fri, 3 Feb 2023 20:23:53 +0800 Subject: [PATCH] feat: @benwoo1110 Revamp content display API commit 1211dfb0574a5d49740b3922147bbcc23540decc Author: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Tue Aug 17 16:29:31 2021 +0800 Implement suggested improvements. * Use singleton pattern for DefaultContentFilter with getInstance method. * Have a default SendHandler. * Don't need streams for small dataset. * Private WorldListContentParser class to improve readability. commit 562eed82558eadb9107557823ae170f6352f8cb2 Author: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Tue Aug 17 00:26:57 2021 +0800 Revamp content display API. --- .../commandsold/GamerulesCommand.java | 48 ++- .../commandsold/ListCommand.java | 107 +++---- .../display/ColorAlternator.java | 62 ---- .../MultiverseCore/display/ColorTool.java | 22 -- .../display/ContentDisplay.java | 273 +++--------------- .../MultiverseCore/display/ContentFilter.java | 153 ---------- .../display/DisplayFormatException.java | 25 -- .../display/DisplayHandler.java | 68 ----- .../display/DisplayHandlers.java | 47 --- .../display/filters/ContentFilter.java | 21 ++ .../display/filters/DefaultContentFilter.java | 35 +++ .../display/filters/RegexContentFilter.java | 99 +++++++ .../display/handlers/BaseSendHandler.java | 99 +++++++ .../display/handlers/DefaultSendHandler.java | 29 ++ .../handlers/InlineListDisplayHandler.java | 36 --- .../handlers/InlineMapDisplayHandler.java | 44 --- .../display/handlers/InlineSendHandler.java | 53 ++++ .../display/handlers/ListDisplayHandler.java | 22 -- .../handlers/PagedListDisplayHandler.java | 105 ------- .../display/handlers/PagedSendHandler.java | 170 +++++++++++ .../display/handlers/SendHandler.java | 20 ++ .../display/parsers/ContentParser.java | 20 ++ .../display/parsers/ListContentParser.java | 60 ++++ .../display/parsers/MapContentParser.java | 112 +++++++ .../display/settings/DisplaySetting.java | 19 -- .../settings/InlineDisplaySettings.java | 15 - .../display/settings/MapDisplaySettings.java | 15 - .../settings/PagedDisplaySettings.java | 30 -- 28 files changed, 841 insertions(+), 968 deletions(-) delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/ColorAlternator.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/ColorTool.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/ContentFilter.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/DisplayFormatException.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandler.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandlers.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/filters/ContentFilter.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/filters/DefaultContentFilter.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/filters/RegexContentFilter.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/BaseSendHandler.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/DefaultSendHandler.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineListDisplayHandler.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineMapDisplayHandler.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineSendHandler.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/ListDisplayHandler.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedListDisplayHandler.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/handlers/SendHandler.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/parsers/ContentParser.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/parsers/ListContentParser.java create mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/parsers/MapContentParser.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/settings/DisplaySetting.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/settings/InlineDisplaySettings.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/settings/MapDisplaySettings.java delete mode 100644 src/main/java/com/onarandombox/MultiverseCore/display/settings/PagedDisplaySettings.java diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandsold/GamerulesCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commandsold/GamerulesCommand.java index ade81ae4..4a8726df 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandsold/GamerulesCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandsold/GamerulesCommand.java @@ -8,9 +8,12 @@ package com.onarandombox.MultiverseCore.commandsold; import com.onarandombox.MultiverseCore.MultiverseCore; -import com.onarandombox.MultiverseCore.display.ColorAlternator; import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.settings.MapDisplaySettings; +import com.onarandombox.MultiverseCore.display.filters.ContentFilter; +import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; +import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter; +import com.onarandombox.MultiverseCore.display.handlers.InlineSendHandler; +import com.onarandombox.MultiverseCore.display.parsers.MapContentParser; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.GameRule; @@ -31,8 +34,8 @@ public class GamerulesCommand extends MultiverseCommand { public GamerulesCommand(MultiverseCore plugin) { super(plugin); this.setName("List the Minecraft Game Rules for a World."); - this.setCommandUsage("/mv gamerules" + ChatColor.GOLD + " [WORLD]"); - this.setArgRange(0, 1); + this.setCommandUsage("/mv gamerules" + ChatColor.GOLD + " [WORLD] [FILTER]"); + this.setArgRange(0, 2); this.addKey("mv gamerules"); this.addKey("mv rules"); this.addKey("mvgamerules"); @@ -42,11 +45,13 @@ public class GamerulesCommand extends MultiverseCommand { this.setPermission("multiverse.core.gamerule.list", "Allows a player to list gamerules.", PermissionDefault.OP); } - @Override public void runCommand(CommandSender sender, List args) { // We NEED a world from the command line - final Player p; + Player p; + World world; + ContentFilter filter = DefaultContentFilter.getInstance(); + if (sender instanceof Player) { p = (Player) sender; } else { @@ -61,9 +66,20 @@ public class GamerulesCommand extends MultiverseCommand { return; } - final World world; + // Not the best way, need to fix with ACF soon... if (args.size() == 0) { world = p.getWorld(); + } else if (args.size() == 1) { + world = Bukkit.getWorld(args.get(0)); + if (world == null) { + if (p == null) { + sender.sendMessage(ChatColor.RED + "Failure!" + ChatColor.WHITE + " World " + ChatColor.AQUA + args.get(0) + + ChatColor.WHITE + " does not exist."); + return; + } + world = p.getWorld(); + filter = RegexContentFilter.fromString(args.get(0)); + } } else { world = Bukkit.getWorld(args.get(0)); if (world == null) { @@ -71,23 +87,23 @@ public class GamerulesCommand extends MultiverseCommand { + ChatColor.WHITE + " does not exist."); return; } + filter = RegexContentFilter.fromString(args.get(1)); } - ContentDisplay.forContent(getGameRuleMap(world)) - .header("=== Gamerules for %s%s%s ===", ChatColor.AQUA, world.getName(), ChatColor.WHITE) - .colorTool(ColorAlternator.with(ChatColor.GREEN, ChatColor.GOLD)) - .setting(MapDisplaySettings.OPERATOR, ": ") - .show(sender); + ContentDisplay.create() + .addContentParser(MapContentParser.forContent(getGameRuleMap(world)) + .withKeyColor(ChatColor.GREEN) + .withValueColor(ChatColor.YELLOW)) + .withSendHandler(InlineSendHandler.create() + .withHeader("====[ Gamerules for %s%s%s ]====", ChatColor.AQUA, world.getName(), ChatColor.WHITE) + .withFilter(filter)) + .send(sender); } private Map getGameRuleMap(World world) { Map gameRuleMap = new HashMap<>(); for (GameRule rule : GameRule.values()) { Object value = world.getGameRuleValue(rule); - if (value == null) { - gameRuleMap.put(rule.getName(), "null"); - continue; - } gameRuleMap.put(rule.getName(), value); } return gameRuleMap; diff --git a/src/main/java/com/onarandombox/MultiverseCore/commandsold/ListCommand.java b/src/main/java/com/onarandombox/MultiverseCore/commandsold/ListCommand.java index c43c7fa5..9b6c1a73 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/commandsold/ListCommand.java +++ b/src/main/java/com/onarandombox/MultiverseCore/commandsold/ListCommand.java @@ -9,11 +9,12 @@ package com.onarandombox.MultiverseCore.commandsold; import com.onarandombox.MultiverseCore.MultiverseCore; import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.onarandombox.MultiverseCore.display.ColorAlternator; import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.ContentFilter; -import com.onarandombox.MultiverseCore.display.DisplayHandlers; -import com.onarandombox.MultiverseCore.display.settings.PagedDisplaySettings; +import com.onarandombox.MultiverseCore.display.filters.ContentFilter; +import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; +import com.onarandombox.MultiverseCore.display.filters.RegexContentFilter; +import com.onarandombox.MultiverseCore.display.handlers.PagedSendHandler; +import com.onarandombox.MultiverseCore.display.parsers.ContentParser; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.command.CommandSender; @@ -21,9 +22,7 @@ import org.bukkit.entity.Player; import org.bukkit.permissions.PermissionDefault; import org.jetbrains.annotations.NotNull; -import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; /** * Displays a listing of all worlds that a player can enter. @@ -43,7 +42,7 @@ public class ListCommand extends MultiverseCommand { @Override public void runCommand(CommandSender sender, List args) { - ContentFilter filter = ContentFilter.DEFAULT; + ContentFilter filter = DefaultContentFilter.getInstance(); int page = 1; // Either page or filter. @@ -51,13 +50,13 @@ public class ListCommand extends MultiverseCommand { try { page = Integer.parseInt(args.get(0)); } catch (NumberFormatException ignore) { - filter = new ContentFilter(args.get(0)); + filter = RegexContentFilter.fromString(args.get(0)); } } // Filter then page. if (args.size() == 2) { - filter = new ContentFilter(args.get(0)); + filter = RegexContentFilter.fromString(args.get(0)); try { page = Integer.parseInt(args.get(1)); } catch (NumberFormatException ignore) { @@ -65,55 +64,57 @@ public class ListCommand extends MultiverseCommand { } } - ContentDisplay.forContent(getListContents(sender)) - .header("%s====[ Multiverse World List ]====", ChatColor.GOLD) - .displayHandler(DisplayHandlers.PAGE_LIST) - .colorTool(ColorAlternator.with(ChatColor.AQUA, ChatColor.GOLD)) - .filter(filter) - .setting(PagedDisplaySettings.SHOW_PAGE, page) - .show(sender); + ContentDisplay.create() + .addContentParser(new WorldListContentParser()) + .withSendHandler(PagedSendHandler.create() + .withHeader("%s====[ Multiverse World List ]====", ChatColor.GOLD) + .withFilter(filter) + .withTargetPage(page)) + .send(sender); } - private Collection getListContents(@NotNull CommandSender sender) { - Player player = (sender instanceof Player) ? (Player) sender : null; + private class WorldListContentParser implements ContentParser { - List worldList = this.plugin.getMVWorldManager().getMVWorlds().stream() - .filter(world -> player == null || plugin.getMVPerms().canEnterWorld(player, world)) - .filter(world -> canSeeWorld(player, world)) - .map(world -> hiddenText(world) + world.getColoredWorldString() + " - " + parseColouredEnvironment(world.getEnvironment())) - .collect(Collectors.toList()); + @Override + public void parse(@NotNull CommandSender sender, @NotNull List content) { + Player player = (sender instanceof Player) ? (Player) sender : null; - this.plugin.getMVWorldManager().getUnloadedWorlds().stream() - .filter(world -> plugin.getMVPerms().hasPermission(sender, "multiverse.access." + world, true)) - .map(world -> ChatColor.GRAY + world + " - UNLOADED") - .forEach(worldList::add); - - return worldList; - } + plugin.getMVWorldManager().getMVWorlds().stream() + .filter(world -> player == null || plugin.getMVPerms().canEnterWorld(player, world)) + .filter(world -> canSeeWorld(player, world)) + .map(world -> hiddenText(world) + world.getColoredWorldString() + " - " + parseColouredEnvironment(world.getEnvironment())) + .forEach(content::add); - private boolean canSeeWorld(Player player, MultiverseWorld world) { - return !world.isHidden() - || player == null - || this.plugin.getMVPerms().hasPermission(player, "multiverse.core.modify", true); - } - - private String hiddenText(MultiverseWorld world) { - return (world.isHidden()) ? String.format("%s[H] ", ChatColor.GRAY) : ""; - } - - private String parseColouredEnvironment(World.Environment env) { - ChatColor color = ChatColor.GOLD; - switch (env) { - case NETHER: - color = ChatColor.RED; - break; - case NORMAL: - color = ChatColor.GREEN; - break; - case THE_END: - color = ChatColor.AQUA; - break; + plugin.getMVWorldManager().getUnloadedWorlds().stream() + .filter(world -> plugin.getMVPerms().hasPermission(sender, "multiverse.access." + world, true)) + .map(world -> ChatColor.GRAY + world + " - UNLOADED") + .forEach(content::add); + } + + private boolean canSeeWorld(Player player, MultiverseWorld world) { + return !world.isHidden() + || player == null + || plugin.getMVPerms().hasPermission(player, "multiverse.core.modify", true); + } + + private String hiddenText(MultiverseWorld world) { + return (world.isHidden()) ? String.format("%s[H] ", ChatColor.GRAY) : ""; + } + + private String parseColouredEnvironment(World.Environment env) { + ChatColor color = ChatColor.GOLD; + switch (env) { + case NETHER: + color = ChatColor.RED; + break; + case NORMAL: + color = ChatColor.GREEN; + break; + case THE_END: + color = ChatColor.AQUA; + break; + } + return color + env.toString(); } - return color + env.toString(); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/ColorAlternator.java b/src/main/java/com/onarandombox/MultiverseCore/display/ColorAlternator.java deleted file mode 100644 index 561394a9..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/ColorAlternator.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -import org.bukkit.ChatColor; -import org.jetbrains.annotations.NotNull; - -/** - * Helper class to switch between 2 {@link ChatColor}. - */ -public class ColorAlternator implements ColorTool { - - /** - * Creates a new {@link ColorAlternator} with 2 {@link ChatColor}s. - * - * @param colorThis The first color. - * @param colorThat The second color. - * @return The {@link ColorAlternator} created for you. - */ - public static ColorAlternator with(@NotNull ChatColor colorThis, - @NotNull ChatColor colorThat) { - - return new ColorAlternator(colorThis, colorThat); - } - - private boolean switcher; - private final ChatColor thisColor; - private final ChatColor thatColor; - - /** - * @param colorThis The first color. - * @param colorThat The second color. - */ - public ColorAlternator(@NotNull ChatColor colorThis, - @NotNull ChatColor colorThat) { - - this.thisColor = colorThis; - this.thatColor = colorThat; - } - - /** - * Gets the color. Everytime this method is called, it swaps the color that it returns. - * - * @return The color. - */ - @Override - public ChatColor get() { - return (this.switcher ^= true) ? this.thisColor : this.thatColor; - } - - /** - * @return The first color. - */ - public ChatColor getThisColor() { - return thisColor; - } - - /** - * @return The second color. - */ - public ChatColor getThatColor() { - return thatColor; - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/ColorTool.java b/src/main/java/com/onarandombox/MultiverseCore/display/ColorTool.java deleted file mode 100644 index 1c4fae67..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/ColorTool.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -import org.bukkit.ChatColor; - -/** - * Tools to allow customisation. - */ -@FunctionalInterface -public interface ColorTool { - - /** - * Gets a chat color. - * - * @return The color. - */ - ChatColor get(); - - /** - * Default implementation of this interface. Returns a default white color. - */ - ColorTool DEFAULT = () -> ChatColor.WHITE; -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/ContentDisplay.java b/src/main/java/com/onarandombox/MultiverseCore/display/ContentDisplay.java index c5d9e39c..b2303c54 100644 --- a/src/main/java/com/onarandombox/MultiverseCore/display/ContentDisplay.java +++ b/src/main/java/com/onarandombox/MultiverseCore/display/ContentDisplay.java @@ -1,268 +1,69 @@ package com.onarandombox.MultiverseCore.display; -import com.onarandombox.MultiverseCore.display.settings.DisplaySetting; -import org.bukkit.ChatColor; +import com.onarandombox.MultiverseCore.display.handlers.DefaultSendHandler; +import com.onarandombox.MultiverseCore.display.handlers.SendHandler; +import com.onarandombox.MultiverseCore.display.parsers.ContentParser; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; -import java.util.Collection; -import java.util.Map; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; -import java.util.WeakHashMap; /** * Helps to display contents such as list and maps in a nicely formatted fashion. - * - * @param Type of content to display. */ -public class ContentDisplay { - - public static final String LINE_BREAK = "%br%"; +public class ContentDisplay { /** - * Creates a ContentDisplay.Builder for the given content. + * Makes a new {@link ContentDisplay} instance to use. * - * @param content The content to be displayed. - * @param The type of the content which can be inferred. - * @return A new Builder. - */ - public static Builder forContent(T content) { - return new Builder<>(content); - } - - /** - * Creates a ContentDisplay.Builder for the given collection of content. - * - * @param content The content to be displayed. - * @return A new Builder. - */ - public static Builder> forContent(Collection content) { - return new Builder<>(content).displayHandler(DisplayHandlers.LIST); - } - - /** - * Creates a ContentDisplay.Builder for the given map of content. - * - * @param content The content to be displayed. - * @return A new Builder. - */ - public static Builder> forContent(Map content) { - return new Builder<>(content).displayHandler(DisplayHandlers.INLINE_MAP); - } - - private final T contents; - - private String header; - private String emptyMessage = "No matching content to display."; - private DisplayHandler displayHandler; - private ColorTool colorTool = ColorTool.DEFAULT; - private ContentFilter filter = ContentFilter.DEFAULT; - private final Map, Object> settingsMap = new WeakHashMap<>(); - - private ContentDisplay(T contents) { - this.contents = contents; - } - - /** - * Do the actual displaying of contents to the sender. - * - * @param sender The CommandSender to show the display to. - */ - public void show(@NotNull CommandSender sender) { - Collection formattedContent; - try { - formattedContent = (this.contents == null) ? null : this.displayHandler.format(sender, this); - } catch (DisplayFormatException e) { - sender.sendMessage(String.format("%sError: %s", ChatColor.RED, e.getMessage())); - return; - } - this.displayHandler.sendHeader(sender, this); - this.displayHandler.sendSubHeader(sender, this); - this.displayHandler.sendBody(sender, this, formattedContent); - } - - /** - * @return Gets the header to display. - */ - public String getHeader() { - return header; - } - - /** - * Sets the header text. - */ - public void setHeader(@NotNull String header) { - this.header = header; - } - - /** - * @return Gets the contents to display. - */ - public T getContents() { - return contents; - } - - /** - * @return Gets the message to display when no content is shown. + * @return New {@link ContentDisplay} instance. */ @NotNull - public String getEmptyMessage() { - return emptyMessage; + public static ContentDisplay create() { + return new ContentDisplay(); + } + + private final List contentParsers = new ArrayList<>(); + private SendHandler sendHandler = DefaultSendHandler.getInstance(); + + public ContentDisplay() { } /** - * @return Gets the display handler that formats and sends content to sender. + * Adds content to be displayed. + * + * @param parser The content parser to add. + * @return Same {@link ContentDisplay} for method chaining. */ @NotNull - public DisplayHandler getDisplayHandler() { - return displayHandler; + public ContentDisplay addContentParser(@NotNull ContentParser parser) { + contentParsers.add(parser); + return this; } /** - * @return Gets the color tool used. + * Sets the handler for displaying the message to command sender. + * + * @param handler The send handler to use. + * @return Same {@link ContentDisplay} for method chaining. */ @NotNull - public ColorTool getColorTool() { - return colorTool; + public ContentDisplay withSendHandler(@NotNull SendHandler handler) { + sendHandler = handler; + return this; } /** - * @return Gets the filter used. - */ - @NotNull - public ContentFilter getFilter() { - return filter; - } - - /** - * Gets the value for a given setting option. + * Format and display the message to command sender. * - * @param setting The setting option. - * @param The setting type. - * @return Value set for the given setting. + * @param sender The target command sender to show the display to. */ - public S getSetting(@NotNull DisplaySetting setting) { - return (S) settingsMap.getOrDefault(setting, setting.defaultValue()); - } - - /** - * Sets other specific settings that may be used by the {@link DisplayHandler}. - * - * @param setting The settings option. - * @param value The value to set. - * @param The type of setting. - */ - public void setSetting(@NotNull DisplaySetting setting, S value) { - this.settingsMap.put(setting, value); - } - - /** - * Builds a {@link ContentDisplay}. - * - * @param Type of content to display. - */ - public static class Builder { - - private final ContentDisplay display; - - private Builder(T content) { - this.display = new ContentDisplay<>(content); - } - - /** - * Sets header to be displayed. - * - * @param header The header text. - * @param replacements String formatting replacements. - * @return The builder. - */ - @NotNull - public Builder header(@NotNull String header, Object...replacements) { - this.display.header = String.format(header, replacements); - return this; - } - - /** - * Sets the message to show when no content is available for display. - * - * @param emptyMessage The message text. - * @param replacements String formatting replacements. - * @return The builder. - */ - @NotNull - public Builder emptyMessage(@NotNull String emptyMessage, Object...replacements) { - this.display.emptyMessage = String.format(emptyMessage, replacements); - return this; - } - - /** - * Sets the display handler that does the formatting and sending of content. Required. - * - * @param displayHandler The display handler for the given content type. - * @return The builder. - */ - @NotNull - public Builder displayHandler(@NotNull DisplayHandler displayHandler) { - this.display.displayHandler = displayHandler; - return this; - } - - /** - * Sets the color tool used to make messages more colourful. - * - * @param colorTool The color tool to use. - * @return The builder. - */ - @NotNull - public Builder colorTool(@NotNull ColorTool colorTool) { - this.display.colorTool = colorTool; - return this; - } - - /** - * Sets content filter used to match specific content to be displayed. - * - * @param filter The filter to use. - * @return The builder. - */ - @NotNull - public Builder filter(@NotNull ContentFilter filter) { - this.display.filter = filter; - return this; - } - - /** - * Sets other specific settings that may be used by the {@link DisplayHandler}. - * - * @param setting The settings option. - * @param value The value to set. - * @param The type of setting. - * @return The builder. - */ - @NotNull - public Builder setting(@NotNull DisplaySetting setting, S value) { - this.display.settingsMap.put(setting, value); - return this; - } - - /** - * Validates and build the content display. - * - * @return The content display. - */ - @NotNull - public ContentDisplay build() { - Objects.requireNonNull(this.display.displayHandler); - return this.display; - } - - /** - * Build and show the content to the sender. - * - * @param sender The CommandSender to show the display to. - */ - public void show(CommandSender sender) { - this.build().show(sender); - } + public void send(@NotNull CommandSender sender) { + Objects.requireNonNull(sendHandler, "No send handler set for content display"); + List parsedContent = new ArrayList<>(); + contentParsers.forEach(parser -> parser.parse(sender, parsedContent)); + sendHandler.send(sender, parsedContent); } } diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/ContentFilter.java b/src/main/java/com/onarandombox/MultiverseCore/display/ContentFilter.java deleted file mode 100644 index cd0bed8c..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/ContentFilter.java +++ /dev/null @@ -1,153 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -import com.dumptruckman.minecraft.util.Logging; -import org.bukkit.ChatColor; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -/** - *

Filter content and text based on regex matching.

- * - *

Compile regex pattern based on {@link ContentFilter#filterString}. When prefixed with 'r=', - * use {@link ContentFilter#filterString} as the full regex pattern. Else, set to any match that - * contains the {@link ContentFilter#filterString}.

- */ -public class ContentFilter { - - public static final ContentFilter DEFAULT = new ContentFilter(); - private static final Pattern REGEX_SPECIAL_CHARS = Pattern.compile("[.+*?\\[^\\]$(){}=!<>|:-\\\\]"); - - private String filterString; - private Pattern filterPattern; - private boolean exactMatch; - - private ContentFilter() { - } - - /** - * @param filterString The text to do matching, either plaintext or regex. - */ - public ContentFilter(@NotNull String filterString) { - this(filterString, false); - } - - /** - * @param filterString The text to do matching, else plaintext or regex. - * @param exactMatch Should check for exact match when doing regex matching. - */ - public ContentFilter(@NotNull String filterString, - boolean exactMatch) { - - this.filterString = filterString; - this.exactMatch = exactMatch; - parseFilter(); - } - - private void parseFilter() { - if (filterString == null) { - return; - } - if (filterString.startsWith("r=")) { - convertToMatcher(filterString.substring(2)); - return; - } - String cleanedFilter = REGEX_SPECIAL_CHARS.matcher(filterString.toLowerCase()).replaceAll("\\\\$0"); - convertToMatcher("(?i).*" + cleanedFilter + ".*"); - } - - /** - * Compile and store the regex into a {@link Pattern}. - * - * @param regex The regex text. - */ - private void convertToMatcher(@NotNull String regex) { - try { - this.filterPattern = Pattern.compile(regex); - Logging.finest("Parsed regex pattern: %s", this.filterPattern.toString()); - } - catch (PatternSyntaxException ignored) { - Logging.warning("Error parsing regex: %s", filterString); - } - } - - /** - * Do regex matching. - * - * @param text String to check regex on. - * @return True of matches regex pattern, false otherwise. - */ - public boolean checkMatch(@Nullable Object text) { - if (!hasFilter()) { - return true; - } - if (text == null || !hasValidPattern()) { - return false; - } - text = ChatColor.stripColor(String.valueOf(text)); - return (exactMatch) - ? filterPattern.matcher((CharSequence) text).matches() - : filterPattern.matcher((CharSequence) text).find(); - } - - /** - * Checks if a filter string is present. - * - * @return True if there is a filter string, else false. - */ - public boolean hasFilter() { - return filterString != null; - } - - /** - * Checks if regex pattern syntax is valid. - * - * @return True if valid, else false. - */ - public boolean hasValidPattern() { - return filterPattern != null; - } - - /** - * @return The filter string. - */ - @Nullable - public String getString() { - return filterString; - } - - /** - * @return The regex pattern. - */ - @Nullable - public Pattern getPattern() { - return filterPattern; - } - - /** - * @return True if filter is set to do exact matching, else false. - */ - public boolean isExactMatch() { - return exactMatch; - } - - /** - * Nicely format the filter string to be used for showing the sender. - * - * @return The formatted filter string. - */ - public @NotNull String getFormattedString() { - return String.format("%sFilter: '%s'", ChatColor.ITALIC, filterString); - } - - @Override - public String toString() { - return "ContentFilter{" + - "filterString='" + filterString + '\'' + - ", filterPattern=" + filterPattern + - ", exactMatch=" + exactMatch + - '}'; - } -} \ No newline at end of file diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayFormatException.java b/src/main/java/com/onarandombox/MultiverseCore/display/DisplayFormatException.java deleted file mode 100644 index 604d6acd..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayFormatException.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -/** - * Thrown when an issue occur while formatting content. - */ -public class DisplayFormatException extends Exception { - public DisplayFormatException() { - } - - public DisplayFormatException(String message) { - super(message); - } - - public DisplayFormatException(String message, Throwable cause) { - super(message, cause); - } - - public DisplayFormatException(Throwable cause) { - super(cause); - } - - public DisplayFormatException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandler.java deleted file mode 100644 index 7971a11f..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandler.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -import com.google.common.base.Strings; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; - -/** - * Handles the formatting and sending of all content by the {@link ContentDisplay}. - * - * @param Type of content to display. - */ -@FunctionalInterface -public interface DisplayHandler { - - /** - * Formats the raw content into a {@link Collection} for displaying to the given sender. - * - * @param sender The {@link CommandSender} who will the content will be displayed to. - * @param display The responsible {@link ContentDisplay}. - * @return The formatted content. - * @throws DisplayFormatException Issue occurred while formatting content. E.g. invalid page. - */ - Collection format(@NotNull CommandSender sender, @NotNull ContentDisplay display) - throws DisplayFormatException; - - /** - * Sends the header. - * - * @param sender The {@link CommandSender} who will the header will be displayed to. - * @param display The responsible {@link ContentDisplay}. - */ - default void sendHeader(@NotNull CommandSender sender, @NotNull ContentDisplay display) { - if (!Strings.isNullOrEmpty(display.getHeader())) { - sender.sendMessage(display.getHeader()); - } - } - - /** - * Sends info such as filter and page. - * - * @param sender The {@link CommandSender} who will the sub header will be displayed to. - * @param display The responsible {@link ContentDisplay}. - */ - default void sendSubHeader(@NotNull CommandSender sender, @NotNull ContentDisplay display) { - if (display.getFilter().hasFilter()) { - sender.sendMessage(String.format("%s[ %s ]", ChatColor.GRAY, display.getFilter().getFormattedString())); - } - } - - /** - * Sends the content. - * - * @param sender The {@link CommandSender} who will the body will be displayed to. - * @param display The responsible {@link ContentDisplay}. - * @param formattedContent The content after being formatted by {@link #format(CommandSender, ContentDisplay)} - */ - default void sendBody(@NotNull CommandSender sender, @NotNull ContentDisplay display, - Collection formattedContent) { - if (formattedContent == null || formattedContent.size() == 0) { - sender.sendMessage(display.getEmptyMessage()); - return; - } - sender.sendMessage(formattedContent.toArray(new String[0])); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandlers.java b/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandlers.java deleted file mode 100644 index 7343c6ad..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/DisplayHandlers.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.onarandombox.MultiverseCore.display; - -import com.onarandombox.MultiverseCore.display.handlers.InlineListDisplayHandler; -import com.onarandombox.MultiverseCore.display.handlers.InlineMapDisplayHandler; -import com.onarandombox.MultiverseCore.display.handlers.ListDisplayHandler; -import com.onarandombox.MultiverseCore.display.handlers.PagedListDisplayHandler; -import com.onarandombox.MultiverseCore.display.settings.InlineDisplaySettings; -import com.onarandombox.MultiverseCore.display.settings.PagedDisplaySettings; -import com.onarandombox.MultiverseCore.display.settings.MapDisplaySettings; - -import java.util.Collection; -import java.util.Map; - -/** - * Various implementations of {@link DisplayHandler}. - */ -public class DisplayHandlers { - - /** - * Standard list display. - * - * Supported settings: none. - */ - public static final DisplayHandler> LIST = new ListDisplayHandler(); - - /** - * List display with paging. - * - * Supported settings: {@link PagedDisplaySettings#SHOW_PAGE}, {@link PagedDisplaySettings#LINES_PER_PAGE}, - * {@link PagedDisplaySettings#PAGE_IN_CONSOLE}, {@link PagedDisplaySettings#DO_END_PADDING}. - */ - public static final DisplayHandler> PAGE_LIST = new PagedListDisplayHandler(); - - /** - * Display a list inline. - * - * Supported settings: {@link InlineDisplaySettings#SEPARATOR}. - */ - public static final DisplayHandler> INLINE_LIST = new InlineListDisplayHandler(); - - /** - * Display key value pair inline. - * - * Supported settings: {@link InlineDisplaySettings#SEPARATOR}, {@link MapDisplaySettings#OPERATOR}. - */ - public static final DisplayHandler> INLINE_MAP = new InlineMapDisplayHandler(); -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/filters/ContentFilter.java b/src/main/java/com/onarandombox/MultiverseCore/display/filters/ContentFilter.java new file mode 100644 index 00000000..240d7d92 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/filters/ContentFilter.java @@ -0,0 +1,21 @@ +package com.onarandombox.MultiverseCore.display.filters; + +/** + * Filter display content for it show only certain string. + */ +public interface ContentFilter { + /** + * Checks if a particular string should be displayed. + * + * @param value String to check on. + * @return True if should be display, false otherwise. + */ + boolean checkMatch(String value); + + /** + * Gets whether content needs to be filtered by this filter. + * + * @return True if content should be filtered, false otherwise. + */ + boolean needToFilter(); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/filters/DefaultContentFilter.java b/src/main/java/com/onarandombox/MultiverseCore/display/filters/DefaultContentFilter.java new file mode 100644 index 00000000..5070d647 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/filters/DefaultContentFilter.java @@ -0,0 +1,35 @@ +package com.onarandombox.MultiverseCore.display.filters; + +/** + * Default implementation of {@link ContentFilter} that doesn't filter anything. + */ +public class DefaultContentFilter implements ContentFilter { + + public static DefaultContentFilter instance; + + public static DefaultContentFilter getInstance() { + if (instance == null) { + instance = new DefaultContentFilter(); + } + return instance; + } + + private DefaultContentFilter() { + } + + /** + * {@inheritDoc} + */ + @Override + public boolean checkMatch(String value) { + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean needToFilter() { + return false; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/filters/RegexContentFilter.java b/src/main/java/com/onarandombox/MultiverseCore/display/filters/RegexContentFilter.java new file mode 100644 index 00000000..e83611e9 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/filters/RegexContentFilter.java @@ -0,0 +1,99 @@ +package com.onarandombox.MultiverseCore.display.filters; + +import com.dumptruckman.minecraft.util.Logging; +import com.google.common.base.Strings; +import org.bukkit.ChatColor; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Filter content and text based on regex matching. + */ +public class RegexContentFilter implements ContentFilter { + + private static final Pattern REGEX_SPECIAL_CHARS = Pattern.compile("[.+*?\\[^\\]$(){}=!<>|:-\\\\]"); + + /** + * Compile regex pattern to create a regex filter. + * + * When prefixed with 'r=', filter string is used as the full regex pattern. + * Else, set to regex that contains the filterString. + * + * @param filterString The target string to create filter. + * @return A new instance of {@link RegexContentFilter} with filter applied. + */ + @NotNull + public static RegexContentFilter fromString(@Nullable String filterString) { + if (filterString == null) { + return new RegexContentFilter(null); + } + if (filterString.startsWith("r=")) { + return new RegexContentFilter(filterString.substring(2)); + } + String cleanedFilter = REGEX_SPECIAL_CHARS.matcher(filterString.toLowerCase()).replaceAll("\\\\$0"); + return new RegexContentFilter("(?i).*" + cleanedFilter + ".*"); + } + + private final String regexString; + private Pattern regexPattern; + + public RegexContentFilter(@Nullable String regexString) { + this.regexString = regexString; + convertToPattern(); + } + + /** + * Try to compile and store the regex into a {@link Pattern}. + */ + private void convertToPattern() { + if (Strings.isNullOrEmpty(regexString)) { + return; + } + try { + regexPattern = Pattern.compile(regexString); + } catch (PatternSyntaxException ignored) { + regexPattern = null; + Logging.fine("Error parsing regex: %s", regexString); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean checkMatch(String value) { + if (!hasValidRegex()) { + return false; + } + String text = ChatColor.stripColor(String.valueOf(value)); + return regexPattern.matcher(text).find(); + } + + /** + * {@inheritDoc} + */ + @Override + public boolean needToFilter() { + return hasValidRegex(); + } + + public boolean hasValidRegex() { + return regexPattern != null; + } + + public String getRegexString() { + return regexString; + } + + public Pattern getRegexPattern() { + return regexPattern; + } + + @Override + public String toString() { + return regexString; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/BaseSendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/BaseSendHandler.java new file mode 100644 index 00000000..46e11b29 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/BaseSendHandler.java @@ -0,0 +1,99 @@ +package com.onarandombox.MultiverseCore.display.handlers; + +import com.google.common.base.Strings; +import com.onarandombox.MultiverseCore.display.filters.ContentFilter; +import com.onarandombox.MultiverseCore.display.filters.DefaultContentFilter; +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * Base implementation of {@link SendHandler} with some common parameters. + * + * @param The subclass that inherited this baseclass. + */ +public abstract class BaseSendHandler> implements SendHandler { + + protected String header = ""; + protected ContentFilter filter = DefaultContentFilter.getInstance(); + + /** + * {@inheritDoc} + */ + @Override + public void send(@NotNull CommandSender sender, @NotNull List content) { + sendHeader(sender); + List filteredContent = filterContent(content); + if (filteredContent.isEmpty()) { + sender.sendMessage(String.format("%sThere is no content to display.", ChatColor.RED)); + return; + } + sendContent(sender, filteredContent); + } + + /** + * Sends the header if header is present. + * + * @param sender The target which the header will be displayed to. + */ + protected void sendHeader(CommandSender sender) { + if (!Strings.isNullOrEmpty(header)) { + sender.sendMessage(header); + } + } + + /** + * Filter to keep only contents that matches the filter. + * + * @param content The content to filter on. + * @return The filtered list of content. + */ + protected List filterContent(@NotNull List content) { + if (filter.needToFilter()) { + return content.stream().filter(filter::checkMatch).collect(Collectors.toList()); + } + return content; + } + + /** + * Display the contents. + * + * @param sender The target which the content will be displayed to. + * @param content The content to display. + */ + protected abstract void sendContent(@NotNull CommandSender sender, @NotNull List content); + + /** + * Sets header to be displayed. + * + * @param header The header text. + * @param replacements String formatting replacements. + * @return Same {@link T} for method chaining. + */ + public T withHeader(@NotNull String header, @NotNull Object...replacements) { + this.header = String.format(header, replacements); + return (T) this; + } + + /** + * Sets content filter used to match specific content to be displayed. + * + * @param filter The filter to use. + * @return Same {@link T} for method chaining. + */ + public T withFilter(@NotNull ContentFilter filter) { + this.filter = filter; + return (T) this; + } + + public String getHeader() { + return header; + } + + public ContentFilter getFilter() { + return filter; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/DefaultSendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/DefaultSendHandler.java new file mode 100644 index 00000000..e0299785 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/DefaultSendHandler.java @@ -0,0 +1,29 @@ +package com.onarandombox.MultiverseCore.display.handlers; + +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class DefaultSendHandler implements SendHandler { + + private static DefaultSendHandler instance; + + public static DefaultSendHandler getInstance() { + if (instance == null) { + instance = new DefaultSendHandler(); + } + return instance; + } + + private DefaultSendHandler() { + } + + /** + * {@inheritDoc} + */ + @Override + public void send(@NotNull CommandSender sender, @NotNull List content) { + sender.sendMessage(content.toArray(new String[0])); + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineListDisplayHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineListDisplayHandler.java deleted file mode 100644 index 53aa196b..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineListDisplayHandler.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.onarandombox.MultiverseCore.display.handlers; - -import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.DisplayFormatException; -import com.onarandombox.MultiverseCore.display.DisplayHandler; -import com.onarandombox.MultiverseCore.display.settings.InlineDisplaySettings; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; - -public class InlineListDisplayHandler implements DisplayHandler> { - - @Override - public Collection format(@NotNull CommandSender sender, @NotNull ContentDisplay> display) - throws DisplayFormatException { - StringBuilder builder = new StringBuilder(); - String separator = display.getSetting(InlineDisplaySettings.SEPARATOR); - - for (Iterator iterator = display.getContents().iterator(); iterator.hasNext(); ) { - String content = iterator.next(); - if (!display.getFilter().checkMatch(content)) { - continue; - } - builder.append(display.getColorTool().get()).append(content); - if (iterator.hasNext()) { - builder.append(separator); - } - } - return (builder.length() == 0) - ? Collections.singletonList(display.getEmptyMessage()) - : Collections.singleton(builder.toString()); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineMapDisplayHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineMapDisplayHandler.java deleted file mode 100644 index 312ccb86..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineMapDisplayHandler.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.onarandombox.MultiverseCore.display.handlers; - -import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.DisplayFormatException; -import com.onarandombox.MultiverseCore.display.DisplayHandler; -import com.onarandombox.MultiverseCore.display.settings.InlineDisplaySettings; -import com.onarandombox.MultiverseCore.display.settings.MapDisplaySettings; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Collections; -import java.util.Iterator; -import java.util.Map; - -public class InlineMapDisplayHandler implements DisplayHandler> { - - @Override - public Collection format(@NotNull CommandSender sender, - @NotNull ContentDisplay> display) - throws DisplayFormatException { - StringBuilder builder = new StringBuilder(); - String separator = display.getSetting(InlineDisplaySettings.SEPARATOR); - String operator = display.getSetting(MapDisplaySettings.OPERATOR); - - for (Iterator> iterator = display.getContents().entrySet().iterator(); iterator.hasNext(); ) { - Map.Entry entry = iterator.next(); - if (!display.getFilter().checkMatch(entry.getKey()) && !display.getFilter().checkMatch(entry.getValue())) { - continue; - } - builder.append(display.getColorTool().get()) - .append(entry.getKey()) - .append(operator) - .append(display.getColorTool().get()) - .append(entry.getValue()); - if (iterator.hasNext()) { - builder.append(separator); - } - } - return (builder.length() == 0) - ? Collections.singletonList(display.getEmptyMessage()) - : Collections.singleton(builder.toString()); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineSendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineSendHandler.java new file mode 100644 index 00000000..5d8a1d10 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/InlineSendHandler.java @@ -0,0 +1,53 @@ +package com.onarandombox.MultiverseCore.display.handlers; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Display the contents in a single line. + */ +public class InlineSendHandler extends BaseSendHandler { + + /** + * Makes a new {@link InlineSendHandler} instance to use. + * + * @return New {@link InlineSendHandler} instance. + */ + public static InlineSendHandler create() { + return new InlineSendHandler(); + } + + private String delimiter = ChatColor.WHITE + ", "; + + public InlineSendHandler() { + } + + /** + * {@inheritDoc} + */ + @Override + public void sendContent(@NotNull CommandSender sender, @NotNull List content) { + if (filter.needToFilter()) { + sender.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter)); + } + sender.sendMessage(String.join(delimiter, content)); + } + + /** + * Sets the delimiter. A sequence of characters that is used to separate each of the elements in content. + * + * @param delimiter The delimiter to use. + * @return Same {@link InlineSendHandler} for method chaining. + */ + public InlineSendHandler withDelimiter(String delimiter) { + this.delimiter = delimiter; + return this; + } + + public String getDelimiter() { + return delimiter; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/ListDisplayHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/ListDisplayHandler.java deleted file mode 100644 index c2b0979f..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/ListDisplayHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.onarandombox.MultiverseCore.display.handlers; - -import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.DisplayFormatException; -import com.onarandombox.MultiverseCore.display.DisplayHandler; -import org.bukkit.command.CommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.stream.Collectors; - -public class ListDisplayHandler implements DisplayHandler> { - - @Override - public Collection format(@NotNull CommandSender sender, @NotNull ContentDisplay> display) - throws DisplayFormatException { - return display.getContents().stream() - .filter(display.getFilter()::checkMatch) - .map(s -> (ContentDisplay.LINE_BREAK.equals(s)) ? "" : display.getColorTool().get() + s) - .collect(Collectors.toList()); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedListDisplayHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedListDisplayHandler.java deleted file mode 100644 index 17f0825e..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedListDisplayHandler.java +++ /dev/null @@ -1,105 +0,0 @@ -package com.onarandombox.MultiverseCore.display.handlers; - -import com.onarandombox.MultiverseCore.display.ContentDisplay; -import com.onarandombox.MultiverseCore.display.DisplayFormatException; -import com.onarandombox.MultiverseCore.display.settings.PagedDisplaySettings; -import org.bukkit.ChatColor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.IntStream; - -public class PagedListDisplayHandler extends ListDisplayHandler { - - @Override - public Collection format(@NotNull CommandSender sender, @NotNull ContentDisplay> display) - throws DisplayFormatException { - if (dontNeedPaging(sender, display)) { - return super.format(sender, display); - } - - int pages = 1; - int currentLength = 0; - int targetPage = display.getSetting(PagedDisplaySettings.SHOW_PAGE); - int linesPerPage = display.getSetting(PagedDisplaySettings.LINES_PER_PAGE); - List content = new ArrayList<>(linesPerPage); - - // Calculate the paging. - for (String line : display.getContents()) { - if (!display.getFilter().checkMatch(line)) { - continue; - } - // When it's the next page. - boolean isLineBreak = ContentDisplay.LINE_BREAK.equals(line); - if (isLineBreak || ++currentLength > linesPerPage) { - pages++; - currentLength = 0; - if (isLineBreak) { - continue; - } - } - if (pages == targetPage) { - // Let first line be the header when no header is defined. - if (display.getHeader() == null) { - display.setHeader(line); - currentLength--; - continue; - } - content.add(display.getColorTool().get() + line); - } - } - - // Page out of range. - if (targetPage < 1 || targetPage > pages) { - if (pages == 1) { - throw new DisplayFormatException("There is only 1 page!"); - } - throw new DisplayFormatException("Please enter a page from 1 to " + pages + "."); - } - - // No content - if (content.size() == 0) { - content.add(display.getEmptyMessage()); - } - - // Add empty lines to make output length consistent. - if (display.getSetting(PagedDisplaySettings.DO_END_PADDING)) { - IntStream.range(0, linesPerPage - content.size()).forEach(i -> content.add("")); - } - display.setSetting(PagedDisplaySettings.TOTAL_PAGE, pages); - - return content; - } - - @Override - public void sendSubHeader(@NotNull CommandSender sender, @NotNull ContentDisplay> display) { - if (dontNeedPaging(sender, display)) { - super.sendSubHeader(sender, display); - return; - } - - if (display.getFilter().hasFilter()) { - sender.sendMessage(String.format("%s[ Page %s of %s, %s ]", - ChatColor.GRAY, - display.getSetting(PagedDisplaySettings.SHOW_PAGE), - display.getSetting(PagedDisplaySettings.TOTAL_PAGE), - display.getFilter().getFormattedString()) - ); - return; - } - sender.sendMessage(String.format("%s[ Page %s of %s ]", - ChatColor.GRAY, - display.getSetting(PagedDisplaySettings.SHOW_PAGE), - display.getSetting(PagedDisplaySettings.TOTAL_PAGE)) - ); - } - - private boolean dontNeedPaging(CommandSender sender, ContentDisplay> display) { - return sender instanceof ConsoleCommandSender - && !display.getSetting(PagedDisplaySettings.PAGE_IN_CONSOLE); - } -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java new file mode 100644 index 00000000..62208b5c --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/PagedSendHandler.java @@ -0,0 +1,170 @@ +package com.onarandombox.MultiverseCore.display.handlers; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Display content as a list with optional pagination. + */ +public class PagedSendHandler extends BaseSendHandler { + + /** + * Makes a new {@link PagedSendHandler} instance to use. + * + * @return New {@link PagedSendHandler} instance. + */ + public static PagedSendHandler create() { + return new PagedSendHandler(); + } + + private boolean paginate = true; + private boolean paginateInConsole = false; + private boolean padEnd = true; + private int linesPerPage = 8; + private int targetPage = 1; + + public PagedSendHandler() { + } + + /** + * {@inheritDoc} + */ + @Override + public void sendContent(@NotNull CommandSender sender, + @NotNull List content) { + + if (!paginate || (sender instanceof ConsoleCommandSender && !paginateInConsole)) { + sendNormal(sender, content); + return; + } + sendPaged(sender, content); + } + + /** + * Send content list without pagination. + * + * @param sender The target which the content will be displayed to. + * @param content The content to display. + */ + private void sendNormal(@NotNull CommandSender sender, + @NotNull List content) { + + if (filter.needToFilter()) { + sender.sendMessage(String.format("%s[Filter '%s']", ChatColor.GRAY, filter)); + } + sender.sendMessage(content.toArray(new String[0])); + } + + /** + * Send content list with pagination. + * + * @param sender The target which the content will be displayed to. + * @param content The content to display. + */ + private void sendPaged(@NotNull CommandSender sender, + @NotNull List content) { + + int totalPages = (content.size() + linesPerPage - 1) / linesPerPage; // Basically just divide round up + if (targetPage < 1 || targetPage > totalPages) { + sender.sendMessage(String.format("%sInvalid page number. Please enter a page number between 1 and %s", ChatColor.RED, totalPages)); + return; + } + + if (filter.needToFilter()) { + sender.sendMessage(String.format("%s[Page %s of %s] [Filter '%s']", ChatColor.GRAY, targetPage, totalPages, filter)); + } else { + sender.sendMessage(String.format("%s[Page %s of %s]", ChatColor.GRAY, targetPage, totalPages)); + } + + int startIndex = (targetPage - 1) * linesPerPage; + int pageEndIndex = startIndex + linesPerPage; + int endIndex = Math.min(pageEndIndex, content.size()); + List pageContent = content.subList(startIndex, endIndex); + if (padEnd) { + for (int i = 0; i < (pageEndIndex - endIndex); i++) { + pageContent.add(""); + } + } + sender.sendMessage(pageContent.toArray(new String[0])); + } + + /** + * Sets whether display output should be paginated. + * + * @param paginate State of doing pagination. + * @return Same {@link PagedSendHandler} for method chaining. + */ + public PagedSendHandler doPagination(boolean paginate) { + this.paginate = paginate; + return this; + } + + /** + * Sets whether display output should be paginated if is for console output. + * This option will be useless of {@link PagedSendHandler#paginate} is set to false. + * + * @param paginateInConsole State of doing pagination in console. + * @return Same {@link PagedSendHandler} for method chaining. + */ + public PagedSendHandler doPaginationInConsole(boolean paginateInConsole) { + this.paginateInConsole = paginateInConsole; + return this; + } + + /** + * Sets whether empty lines should be added if content lines shown is less that {@link PagedSendHandler#linesPerPage}. + * + * @param padEnd State of doing end padding. + * @return Same {@link PagedSendHandler} for method chaining. + */ + public PagedSendHandler doEndPadding(boolean padEnd) { + this.padEnd = padEnd; + return this; + } + + /** + * Sets the max number of lines per page. This excludes header. + * + * @param linesPerPage The number of lines per page. + * @return Same {@link PagedSendHandler} for method chaining. + */ + public PagedSendHandler withLinesPerPage(int linesPerPage) { + this.linesPerPage = linesPerPage; + return this; + } + + /** + * Sets the page number to display. + * + * @param targetPage The target page number to display. + * @return Same {@link PagedSendHandler} for method chaining. + */ + public PagedSendHandler withTargetPage(int targetPage) { + this.targetPage = targetPage; + return this; + } + + public boolean isPaginate() { + return paginate; + } + + public boolean isPaginateInConsole() { + return paginateInConsole; + } + + public boolean isPadEnd() { + return padEnd; + } + + public int getLinesPerPage() { + return linesPerPage; + } + + public int getTargetPage() { + return targetPage; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/handlers/SendHandler.java b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/SendHandler.java new file mode 100644 index 00000000..6c826aa6 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/handlers/SendHandler.java @@ -0,0 +1,20 @@ +package com.onarandombox.MultiverseCore.display.handlers; + +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Handles the sending of all content to the command sender. + */ +@FunctionalInterface +public interface SendHandler { + /** + * Sends all the content to the given command sender. + * + * @param sender The target which the content will be displayed to. + * @param content The content to display. + */ + void send(@NotNull CommandSender sender, @NotNull List content); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ContentParser.java b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ContentParser.java new file mode 100644 index 00000000..b69f7a84 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ContentParser.java @@ -0,0 +1,20 @@ +package com.onarandombox.MultiverseCore.display.parsers; + +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Parse objects into string or list of strings. + */ +@FunctionalInterface +public interface ContentParser { + /** + * Parse the object to string(s) and add it to the content. + * + * @param sender The target which the content will be displayed to. + * @param content The content to display. + */ + void parse(@NotNull CommandSender sender, @NotNull List content); +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ListContentParser.java b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ListContentParser.java new file mode 100644 index 00000000..00a89061 --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/ListContentParser.java @@ -0,0 +1,60 @@ +package com.onarandombox.MultiverseCore.display.parsers; + +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * Simple parser for list object. + * + * @param List element type. + */ +public class ListContentParser implements ContentParser { + + /** + * New list content parser for the given list. + * + * @param list The list object to parse. + * @param List element type. + * @return New {@link MapContentParser} instance. + */ + public static ListContentParser forContent(List list) { + return new ListContentParser<>(list); + } + + private final List list; + + private String format = "%s"; + + public ListContentParser(List list) { + this.list = list; + } + + /** + * {@inheritDoc} + */ + @Override + public void parse(@NotNull CommandSender sender, @NotNull List content) { + list.forEach(element -> content.add(String.format(format, element))); + } + + /** + * Sets the format that will be used to parse each list entry. Uses java string format pattern. + * + * @param format The format to use. + * @return Same {@link ListContentParser} for method chaining. + */ + public ListContentParser withFormat(String format) { + this.format = format; + return this; + } + + public List getList() { + return list; + } + + public String getFormat() { + return format; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/parsers/MapContentParser.java b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/MapContentParser.java new file mode 100644 index 00000000..4aad97bc --- /dev/null +++ b/src/main/java/com/onarandombox/MultiverseCore/display/parsers/MapContentParser.java @@ -0,0 +1,112 @@ +package com.onarandombox.MultiverseCore.display.parsers; + +import org.bukkit.ChatColor; +import org.bukkit.command.CommandSender; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; + +/** + * Simple parser for map object. + * + * @param Key type. + * @param Value type. + */ +public class MapContentParser implements ContentParser { + + /** + * New map content parser for the given map. + * + * @param map The map object to parse. + * @param Key type. + * @param Value type. + * @return New {@link MapContentParser} instance. + */ + public static MapContentParser forContent(Map map) { + return new MapContentParser<>(map); + } + + private final Map map; + + private String format = "%s%s%s%s%s"; + private ChatColor keyColor = ChatColor.WHITE; + private ChatColor valueColor = ChatColor.WHITE; + private String separator = ": "; + + public MapContentParser(Map map) { + this.map = map; + } + + /** + * {@inheritDoc} + */ + @Override + public void parse(@NotNull CommandSender sender, @NotNull List content) { + map.forEach((k, v) -> content.add(String.format(format, keyColor, k, separator, valueColor, v))); + } + + /** + * Sets the format that will be used to parse each map entry. Uses java string format pattern. + * + * @param format The format to use. + * @return Same {@link MapContentParser} for method chaining. + */ + public MapContentParser withFormat(String format) { + this.format = format; + return this; + } + + /** + * Sets the color for the key text. + * + * @param keyColor The color to use. + * @return Same {@link MapContentParser} for method chaining. + */ + public MapContentParser withKeyColor(ChatColor keyColor) { + this.keyColor = keyColor; + return this; + } + + /** + * Sets the color for the value text. + * + * @param valueColor The color to use. + * @return Same {@link MapContentParser} for method chaining. + */ + public MapContentParser withValueColor(ChatColor valueColor) { + this.valueColor = valueColor; + return this; + } + + /** + * Sets the separator between each key value pairing. + * + * @param separator The separator to use. + * @return Same {@link MapContentParser} for method chaining. + */ + public MapContentParser withSeparator(String separator) { + this.separator = separator; + return this; + } + + public Map getMap() { + return map; + } + + public String getFormat() { + return format; + } + + public ChatColor getKeyColor() { + return keyColor; + } + + public ChatColor getValueColor() { + return valueColor; + } + + public String getSeparator() { + return separator; + } +} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/settings/DisplaySetting.java b/src/main/java/com/onarandombox/MultiverseCore/display/settings/DisplaySetting.java deleted file mode 100644 index 232e432b..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/settings/DisplaySetting.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.onarandombox.MultiverseCore.display.settings; - -import com.onarandombox.MultiverseCore.display.DisplayHandler; - -/** - * Represents a setting option that can be used by {@link DisplayHandler}. - * - * @param - */ -@FunctionalInterface -public interface DisplaySetting { - - /** - * Gets the default value of this Display Setting. - * - * @return The default value. - */ - T defaultValue(); -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/settings/InlineDisplaySettings.java b/src/main/java/com/onarandombox/MultiverseCore/display/settings/InlineDisplaySettings.java deleted file mode 100644 index 25661d12..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/settings/InlineDisplaySettings.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.onarandombox.MultiverseCore.display.settings; - -import com.onarandombox.MultiverseCore.display.DisplayHandler; -import org.bukkit.ChatColor; - -/** - * Collection of {@link DisplaySetting} that are used by various {@link DisplayHandler}. - */ -public class InlineDisplaySettings { - - /** - * Inline separator. E.g. '1, 2, 3' - */ - public static final DisplaySetting SEPARATOR = () -> ChatColor.WHITE + ", "; -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/settings/MapDisplaySettings.java b/src/main/java/com/onarandombox/MultiverseCore/display/settings/MapDisplaySettings.java deleted file mode 100644 index a7847395..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/settings/MapDisplaySettings.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.onarandombox.MultiverseCore.display.settings; - -import com.onarandombox.MultiverseCore.display.DisplayHandler; -import org.bukkit.ChatColor; - -/** - * Collection of {@link DisplaySetting} that are used by various {@link DisplayHandler}. - */ -public class MapDisplaySettings { - - /** - * The thing between a key value pair. E.g. 'Me = Smart' - */ - public static final DisplaySetting OPERATOR = () -> ChatColor.WHITE + " = "; -} diff --git a/src/main/java/com/onarandombox/MultiverseCore/display/settings/PagedDisplaySettings.java b/src/main/java/com/onarandombox/MultiverseCore/display/settings/PagedDisplaySettings.java deleted file mode 100644 index bdc12f9f..00000000 --- a/src/main/java/com/onarandombox/MultiverseCore/display/settings/PagedDisplaySettings.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.onarandombox.MultiverseCore.display.settings; - -public class PagedDisplaySettings { - - /** - * Page to display. - */ - public static final DisplaySetting SHOW_PAGE = () -> 1; - - /** - * Total pages available to display. - */ - public static final DisplaySetting TOTAL_PAGE = () -> 1; - - /** - * The max number of lines per page. This excludes header. - */ - public static final DisplaySetting LINES_PER_PAGE = () -> 8; - - /** - * Should add empty lines if content lines shown is less that {@link #LINES_PER_PAGE}. - */ - public static final DisplaySetting DO_END_PADDING = () -> true; - - /** - * Should display with paging when it's sent to console. - */ - public static final DisplaySetting PAGE_IN_CONSOLE = () -> false; - -}