bentobox/src/main/java/world/bentobox/bentobox/api/panels/TabbedPanel.java

214 lines
7.7 KiB
Java

package world.bentobox.bentobox.api.panels;
import java.security.InvalidParameterException;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.TreeMap;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.eclipse.jdt.annotation.NonNull;
import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
import world.bentobox.bentobox.api.user.User;
/**
* Represents a panel with tabs. The top row of the panel is made up of up to 9 icons that are made of {@link world.bentobox.bentobox.api.panels.Tab}s.
* Only the active tab is shown. The panel will auto-refresh when a panel item is clicked, so panel item
* click listeners do not have to actively update the panel. Viewers of the panel who do not have permission
* to see a {@link world.bentobox.bentobox.api.panels.Tab} will not be shown it.
*
* @author tastybento
* @since 1.6.0
*/
public class TabbedPanel extends Panel implements PanelListener {
private static final String PROTECTION_PANEL = "protection.panel.";
private static final long ITEMS_PER_PAGE = 36;
private final TabbedPanelBuilder tpb;
@NonNull
private final BentoBox plugin = BentoBox.getInstance();
private int activeTab;
private int activePage;
private boolean closed;
/**
* Construct the tabbed panel
* @param tpb - tabbed panel builder
*/
public TabbedPanel(TabbedPanelBuilder tpb) {
this.tpb = tpb;
// Set world
this.setWorld(tpb.getWorld());
// Set island context in Panel
this.setIsland(tpb.getIsland());
}
/* (non-Javadoc)
* @see world.bentobox.bentobox.api.panels.PanelListener#refreshPanel()
*/
@Override
public void refreshPanel() {
if (closed) return;
// Called when a player clicks on the panel
openPanel(activeTab, activePage);
// Reset the closed flag
closed = false;
}
/**
* Open the tabbed panel at the starting slot
*/
public void openPanel() {
openPanel(tpb.getStartingSlot(), 0);
}
/**
* Open the tabbed panel
* @param activeTab - the tab to show referenced by the slot (0 through 8)
* @param page - the page of the tab to show (if multi paged)
*/
public void openPanel(int activeTab, int page) {
if (!tpb.getTabs().containsKey(activeTab)) {
// Request to open a non-existent tab
throw new InvalidParameterException("Attempt to open a non-existent tab in a tabbed panel. Missing tab #" + activeTab);
}
if (page < 0) {
// Request to open a non-existent tab
throw new InvalidParameterException("Attempt to open a tab in a tabbed panel to a negative page! " + page);
}
this.activeTab = activeTab;
this.activePage = page;
// The items in the panel
TreeMap<Integer, PanelItem> items = new TreeMap<>();
// Get the tab
Tab tab = tpb.getTabs().get(activeTab);
// Remove any tabs that have no items, if required
if (tpb.isHideIfEmpty()) {
tpb.getTabs().values().removeIf(t -> !t.equals(tab) && t.getPanelItems().stream().noneMatch(Objects::nonNull));
}
// Set up the tabbed header
setupHeader(tab, items);
// Show the active tab
if (tpb.getTabs().containsKey(activeTab)) {
List<PanelItem> panelItems = tab.getPanelItems();
// Adds the flag items
panelItems.stream().filter(Objects::nonNull).skip(page * ITEMS_PER_PAGE).limit(page * ITEMS_PER_PAGE + ITEMS_PER_PAGE).forEach(i -> items.put(items.lastKey() + 1, i));
// set up the footer
setupFooter(items);
// Add forward and backward icons
if (page > 0) {
// Previous page icon
items.put(46, new PanelItemBuilder().icon(Material.ARROW).name(tpb.getUser().getTranslation(PROTECTION_PANEL + "previous")).clickHandler((panel, user1, clickType, slot1) -> {
this.activePage--;
this.refreshPanel();
return true;
}).build());
}
if ((page + 1) * ITEMS_PER_PAGE < panelItems.stream().filter(Objects::nonNull).count()) {
// Next page icon
items.put(52, new PanelItemBuilder().icon(Material.ARROW).name(tpb.getUser().getTranslation(PROTECTION_PANEL + "next")).clickHandler((panel, user1, clickType, slot1) -> {
this.activePage++;
this.refreshPanel();
return true;
}).build());
}
} else {
throw new InvalidParameterException("Unknown tab slot number " + activeTab);
}
// Show it to the player
this.makePanel(tab.getName(), items, tpb.getSize(), tpb.getUser(), this);
}
/**
* Shows the top row of icons
* @param tab - active tab
* @param items - panel builder
*/
private void setupHeader(Tab tab, TreeMap<Integer, PanelItem> items) {
// Set up top
for (int i = 0; i < 9; i++) {
items.put(i, new PanelItemBuilder().icon(plugin.getSettings().getPanelFillerMaterial()).name(" ").build());
}
// Add icons
for (Entry<Integer, Tab> tabPanel : tpb.getTabs().entrySet()) {
// Add the icon to the top row
if (tpb.getUser().hasPermission(tabPanel.getValue().getPermission())) {
PanelItem activeIcon = tabPanel.getValue().getIcon();
// Set the glow of the active tab
activeIcon.setGlow(tabPanel.getValue().equals(tab));
items.put(tabPanel.getKey(), activeIcon);
}
}
// Add any subsidiary icons
items.putAll(tab.getTabIcons());
}
private void setupFooter(TreeMap<Integer, PanelItem> items) {
for (int i = 45; i < 54; i++) {
items.put(i, new PanelItemBuilder().icon(plugin.getSettings().getPanelFillerMaterial()).name(" ").build());
}
}
@Override
public void setup() {
// Not used
}
@Override
public void onInventoryClose(InventoryCloseEvent event) {
// This flag is set every time the inventory is closed or refreshed (closed and opened)
closed = true;
}
@Override
public void onInventoryClick(User user, InventoryClickEvent event) {
// Trap top row tab clicks
if (event.isLeftClick() && tpb.getTabs().containsKey(event.getRawSlot())
&& (tpb.getTabs().get(event.getRawSlot()).getPermission().isEmpty()
|| tpb.getUser().hasPermission(tpb.getTabs().get(event.getRawSlot()).getPermission()) || tpb.getUser().isOp())) {
event.setCancelled(true);
this.openPanel(event.getRawSlot(), 0);
user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_OFF, 1F, 1F);
// Reset the closed flag
closed = false;
}
}
/**
* @return the active tab being shown to the user
*/
public Tab getActiveTab() {
return tpb.getTabs().get(activeTab);
}
/**
* @return the activePage
*/
public int getActivePage() {
return activePage;
}
/**
* @param activePage the activePage to set
*/
public void setActivePage(int activePage) {
this.activePage = activePage;
}
/**
* @param activeTab the activeTab to set
*/
public void setActiveTab(int activeTab) {
this.activeTab = activeTab;
}
}