Package com.bergerkiller.bukkit.common.tab

Source Code of com.bergerkiller.bukkit.common.tab.TabView

package com.bergerkiller.bukkit.common.tab;

import org.bukkit.entity.Player;

import com.bergerkiller.bukkit.common.FromToCounter;
import com.bergerkiller.bukkit.common.internal.CommonPlugin;
import com.bergerkiller.bukkit.common.internal.CommonTabController;
import com.bergerkiller.bukkit.common.utils.CommonUtil;

/**
* Represents a live view of a single Player List a player sees when pressing tab.
* Changes in this view can be sent to multiple players or all players on the server.
* Many methods are available to ease the setting of text and ping values in this view.<br><br>
*
* To obtain a TabView instance, call the {@link #createTab(int, int)} method with the desired
* dimensions of the tab specified. It is only possible to create new tabs this way
* when enabling your plugin. To create new Tab View instances at runtime, call {@link #clone()}
* or {@link #cloneResize(int, int)}. Pay close attention to the Java Docs of these methods!
*/
public abstract class TabView {
  /**
   * The maximum allowed width of a Tab View (amount of columns)
   */
  public static final int MAX_WIDTH = 3;
  /**
   * The maximum allowed height of a Tab View (amount of rows)
   */
  public static final int MAX_HEIGHT = 20;
  /**
   * A ping value constant that shows a single green line.
   */
  public static final int PING_1 = 1000;
  /**
   * A ping value constant that shows two green lines
   */
  public static final int PING_2 = 600;
  /**
   * A ping value constant that shows three green lines
   */
  public static final int PING_3 = 300;
  /**
   * A ping value constant that shows four green lines
   */
  public static final int PING_4 = 150;
  /**
   * A ping value constant that shows five green lines
   */
  public static final int PING_5 = 0;
  /**
   * A ping value constant that shows 'X - no connection'
   */
  public static final int PING_NONE = -1;
  /**
   * A ping value constant that shows all green lines
   */
  public static final int PING_FULL = PING_5;
  /**
   * A ping value constant that represents the default ping value, which is equal to {@link #PING_1}
   */
  public static final int PING_DEFAULT = PING_1;
  /**
   * A text value constant that represents the default 'no text', which shows empty (no) text
   */
  public static final String TEXT_DEFAULT = "";
  /**
   * A TabView constant that denotes the default view, that is, the player names and their ping
   */
  public static final TabView DEFAULT = new TabViewDefault();
  /**
   * A TabView constant that denotes an empty view, where all available slots are cleared
   */
  public static final TabView EMPTY = new TabViewEmpty();

  /**
   * Gets the width of this Tab View
   *
   * @return Tab View width
   */
  public abstract int getWidth();

  /**
   * Gets the height of this Tab View
   *
   * @return Tab View height
   */
  public abstract int getHeight();

  /**
   * Gets the total amount of slots of this Tab View.
   * This is equal to [width x height]
   *
   * @return total slot count
   */
  public int getSlotCount() {
    return getWidth() * getHeight();
  }

  /**
   * Sets the displayed ping of a slot
   *
   * @param x - coordinate of the slot
   * @param y - coordinate of the slot
   * @param ping to display
   */
  public abstract void setPing(int x, int y, int ping);

  /**
   * Sets the displayed text of a slot
   *
   * @param x - coordinate of the slot
   * @param y - coordinate of the slot
   * @param text to display
   */
  public abstract void setText(int x, int y, String text);

  /**
   * Sets the displayed ping and text of a slot
   *
   * @param x - coordinate of the slot
   * @param y - coordinate of the slot
   * @param text to display
   * @param ping to display
   */
  public abstract void set(int x, int y, String text, int ping);

  /**
   * Sets all the text and ping values of a single column. Points outside of the text or ping array
   * bounds are ignored. If the text or ping arrays are null, the values are ignored.
   * The text is set from top to bottom
   *
   * @param column - x-coordinate of the column
   * @param text values, null or empty to ignore
   * @param ping values, null or empty to ignore
   */
  public void setColumn(int column, String[] text, int[] ping) {
    setArea(column, 0, column, getHeight() - 1, text, ping);
  }

  /**
   * Sets all the text and ping values of a single row. Points outside of the text or ping array
   * bounds are ignored. If the text or ping arrays are null, the values are ignored.
   * The text is set from top to bottom<br><br>
   *
   * To set the values in reverse, simply use y2 for y1.
   *
   * @param column - x-coordinate of the column
   * @param y1 - y-coordinate of point 1 (start) of the column (inclusive)
   * @param y2 - y-coordinate of point 2 (end) of the column (inclusive)
   * @param text values, null or empty to ignore
   * @param ping values, null or empty to ignore
   */
  public void setColumn(int column, int y1, int y2, String[] text, int[] ping) {
    setArea(column, y1, column, y2, text, ping);
  }

  /**
   * Sets all the text and ping values of a single row. Points outside of the text or ping array
   * bounds are ignored. If the text or ping arrays are null, the values are ignored.
   * The text is set from left to right
   *
   * @param row - y-coordinate of the row
   * @param text values, null or empty to ignore
   * @param ping values, null or empty to ignore
   */
  public void setRow(int row, String[] text, int[] ping) {
    setArea(0, row, getWidth() - 1, row, text, ping);
  }

  /**
   * Sets all the text and ping values of a single row. Points outside of the text or ping array
   * bounds are ignored. If the text or ping arrays are null, the values are ignored.
   * The text is set from left to right<br><br>
   *
   * To set the values in reverse, simply use x2 for x1.
   *
   * @param row - y-coordinate of the row
   * @param x1 - x-coordinate of point 1 (start) of the row (inclusive)
   * @param x2 - x-coordinate of point 2 (end) of the row (inclusive)
   * @param text values, null or empty to ignore
   * @param ping values, null or empty to ignore
   */
  public void setRow(int row, int x1, int x2, String[] text, int[] ping) {
    setArea(x1, row, x2, row, text, ping);
  }

  /**
   * Sets all the text and ping values of an area. Points outside of the text or ping array
   * bounds are ignored. If the text or ping arrays are null, the values are ignored.
   * The text is set from left to right<br><br>
   *
   * To set the values in reverse, simply use x2 for x1 and y2 for y1.<br><br>
   *
   * @param x1 - x-coordinate of point 1 (inclusive)
   * @param y1 - y-coordinate of point 1 (inclusive)
   * @param x2 - x-coordinate of point 2 (inclusive)
   * @param y2 - y-coordinate of point 2 (inclusive)
   * @param text values, null or empty to ignore
   * @param ping values, null or empty to ignore
   */
  public void setArea(int x1, int y1, int x2, int y2, String[] text, int[] ping) {
    boundsCheck(x1, y1);
    boundsCheck(x2, y2);
    final boolean hasText = text != null && text.length > 0;
    final boolean hasPing = ping != null && ping.length > 0;
    if (!hasText && !hasPing) {
      return;
    }
    // Initialize all counters
    FromToCounter counterX = new FromToCounter(x1, x2);
    FromToCounter counterY = new FromToCounter(y1, y2);
    FromToCounter textCounter = new FromToCounter();
    FromToCounter pingCounter = new FromToCounter();
    if (hasText) {
      textCounter.reset(0, text.length - 1);
    }
    if (hasPing) {
      pingCounter.reset(0, ping.length - 1);
    }
    // Start processing the area
    while (counterX.hasNext()) {
      counterX.next();
      counterY.reset();
      while (counterY.hasNext()) {
        counterY.next();
        if (textCounter.hasNext()) {
          if (pingCounter.hasNext()) {
            // Text and ping are available
            set(counterX.get(), counterY.get(), text[textCounter.next()], ping[pingCounter.next()]);
          } else {
            // Only text is available
            setText(counterX.get(), counterY.get(), text[textCounter.next()]);
          }
        } else if (pingCounter.hasNext()) {
          // Only ping is available
          setPing(counterX.get(), counterY.get(), ping[pingCounter.next()]);
        }
      }
    }
  }

  /**
   * Sets all text and ping values in the area to the text and ping values specified.
   * Ordering of xy1 and xy2 is not important.
   *
   * @param x1 - x-coordinate of point 1 (inclusive)
   * @param y1 - y-coordinate of point 1 (inclusive)
   * @param x2 - x-coordinate of point 2 (inclusive)
   * @param y2 - y-coordinate of point 2 (inclusive)
   * @param text to use
   * @param ping to use
   */
  public void fillArea(int x1, int y1, int x2, int y2, String text, int ping) {
    boundsCheck(x1, y1);
    boundsCheck(x2, y2);
    // Initialize all counters
    FromToCounter counterX = new FromToCounter(x1, x2);
    FromToCounter counterY = new FromToCounter(y1, y2);
    // Start processing the area
    while (counterX.hasNext()) {
      counterX.next();
      counterY.reset();
      while (counterY.hasNext()) {
        counterY.next();
        set(counterX.get(), counterY.get(), text, ping);
      }
    }
  }

  /**
   * Fills an entire row with the text and ping specified.
   *
   * @param row to fill
   * @param x1 - x-coordinate of point 1 of the row (inclusive)
   * @param x2 - x-coordinate of point 2 of the row (inclusive)
   * @param text to use
   * @param ping to use
   */
  public void fillRow(int row, int x1, int x2, String text, int ping) {
    fillArea(x1, row, x2, row, text, ping);
  }

  /**
   * Fills an entire row with the text and ping specified.
   *
   * @param row to fill
   * @param text to use
   * @param ping to use
   */
  public void fillRow(int row, String text, int ping) {
    fillRow(row, 0, getWidth() - 1, text, ping);
  }

  /**
   * Fills an entire column with the text and ping specified.
   *
   * @param column to fill
   * @param y1 - y-coordinate of point 1 of the row (inclusive)
   * @param y2 - y-coordinate of point 2 of the row (inclusive)
   * @param text to use
   * @param ping to use
   */
  public void fillColumn(int column, int y1, int y2, String text, int ping) {
    fillArea(column, y1, column, y2, text, ping);
  }

  /**
   * Fills an entire column with the text and ping specified.
   *
   * @param column to fill
   * @param text to use
   * @param ping to use
   */
  public void fillColumn(int column, String text, int ping) {
    fillColumn(column, 0, getHeight() - 1, text, ping);
  }

  /**
   * Sets all slots of this Tab View to the text and ping values
   *
   * @param text value to set to
   * @param ping value to set to
   */
  public void fillAll(String text, int ping) {
    int x, y;
    for (x = 0; x < getWidth(); x++) {
      for (y = 0; y < getHeight(); y++) {
        set(x, y, text, ping);
      }
    }
  }

  /**
   * Sets all the contents of this Tab View to the text and ping arrays.
   * Elements outside of these arrays or if the arrays are null are not set.
   *
   * @param text array, null or empty to ignore
   * @param ping array, null or empty to ignore
   */
  public void setAll(String[] text, int[] ping) {
    setArea(0, 0, getWidth() - 1, getHeight() - 1, text, ping);
  }

  /**
   * Sets all the contents of this Tab View to contain the contents of the Tab View.
   * If the Tab View is larger than this one, only a portion that can fit in this Tab View
   * is transferred over.
   *
   * @param view to set to
   */
  public void setAll(TabView view) {
    int width = Math.min(this.getWidth(), view.getWidth());
    int height = Math.min(this.getHeight(), view.getHeight());
    int x, y;
    for (x = 0; x < width; x++) {
      for (y = 0; y < height; y++) {
        this.set(x, y, view.getText(x, y), view.getPing(x, y));
      }
    }
  }

  /**
   * Sets all the text values of an area. Points outside of the text array bounds are ignored.
   * If the text array is null, the values are ignored. The text is set from left to right.<br><br>
   *
   * To set the values in reverse, simply use x2 for x1 and y2 for y1.<br><br>
   *
   * This is an overload for
   * {@link #setArea(int, int, int, int, String[], int[]) setArea(x1, y1, x2, y2, text, ping)}
   * to allow variable arguments instead of fixed arrays.
   *
   * @param x1 - x-coordinate of point 1 (inclusive)
   * @param y1 - y-coordinate of point 2 (inclusive)
   * @param x2 - x-coordinate of point 1 (inclusive)
   * @param y2 - y-coordinate of point 2 (inclusive)
   * @param text to set to, null or empty to ignore (nothing happens then)
   */
  public void setAreaText(int x1, int y1, int x2, int y2, String... text) {
    setArea(x1, y1, x2, y2, text, null);
  }

  /**
   * Sets all the text and ping values of a single row.
   * Points outside of the text array bounds are ignored.
   * The text is set from left to right.<br><br>
   *
   * To set the values in reverse, simply use x2 for x1.<br><br>
   *
   * This is an overload for
   * {@link #setRow(int, int, int, String[], int[]) setRow(row, x1, x2, text, ping)}
   * to allow variable arguments instead of fixed arrays.
   *
   * @param row - y-coordinate of the row
   * @param x1 - x-coordinate of point 1 (start) of the row (inclusive)
   * @param x2 - x-coordinate of point 2 (end) of the row (inclusive)
   * @param text
   */
  public void setRowText(int row, int x1, int x2, String... text) {
    this.setRow(row, x1, x2, text, null);
  }

  /**
   * Sets all the text and ping values of a single row.
   * Points outside of the text array bounds are ignored.
   * The text is set from left to right.<br><br>
   *
   * This is an overload for
   * {@link #setRow(int, String[], int[]) setRow(row, text, ping)}
   * to allow variable arguments instead of fixed arrays.
   *
   * @param row to set
   * @param text to set to
   */
  public void setRowText(int row, String... text) {
    this.setRow(row, text, null);
  }

  /**
   * Sets all the text and ping values of a single row.
   * Points outside of the text array bounds are ignored.
   * The text is set from top to bottom.<br><br>
   *
   * To set the values in reverse, simply use y2 for y1.<br><br>
   *
   * This is an overload for
   * {@link #setColumn(int, int, int, String[], int[]) setColumn(column, y1, y2, text, ping)}
   * to allow variable arguments instead of fixed arrays.
   *
   * @param column - x-coordinate of the column
   * @param y1 - y-coordinate of point 1 (start) of the column (inclusive)
   * @param y2 - y-coordinate of point 2 (end) of the column (inclusive)
   * @param text
   */
  public void setColumnText(int column, int y1, int y2, String... text) {
    this.setColumn(column, y1, y2, text, null);
  }

  /**
   * Sets all the text values of a single column. Points outside of the text or ping array
   * bounds are ignored. The text is set from top to bottom.<br><br>
   *
   * This is an overload for
   * {@link #setColumn(int, String[], int[]) setColumn(column, text, ping)}
   * to allow variable arguments instead of fixed arrays.
   *
   * @param column - x-coordinate of the column
   * @param text
   */
  public void setColumnText(int column, String... text) {
    setColumn(column, text, null);
  }

  /**
   * Sets all the text contents of this Tab View to the text array.
   * Elements outside of this array or if the array is null are not set.<br><br>
   *
   * This is an overload of {@link #setAll(String[], int[]) setAll(text, ping)} to allow variable arguments instead of fixed arrays.
   *
   * @param text to set to, null or empty to ignore (nothing happens then)
   */
  public void setAllText(String... text) {
    setAll(text, null);
  }

  /**
   * Gets the text shown in the slot at the x and y coordinates specified
   *
   * @param x - coordinate of the slot
   * @param y - coordinate of the slot
   * @return text set for that slot
   */
  public abstract String getText(int x, int y);

  /**
   * Gets the ping shown in the slot at the x and y coordinates specified
   *
   * @param x - coordinate of the slot
   * @param y - coordinate of the slot
   * @return ping set for that slot
   */
  public abstract int getPing(int x, int y);

  /**
   * Gets whether the current Tab View is displayed to a player
   *
   * @param player to check
   * @return True if this Tab View is displayed to the Player, False if not
   */
  public boolean isDisplayedTo(Player player) {
    return getController().getCurrentTab(player) == this;
  }

  /**
   * Displays this Tab View to the player specified.
   * The player is added to the viewers, previous viewers are not removed.
   * If you wish to hide this Tab View again, use displayTo on the {@link #DEFAULT} or {@link #EMPTY} constants.
   *
   * @param player
   */
  public void displayTo(Player player) {
    getController().showTab(player, this);
  }

  /**
   * Displays this Tab View to all online players and
   * all players that will join in the future.
   */
  public void displayToAll() {
    getController().showTabToAll(this);
  }

  @Override
  public TabView clone() {
    final int width = getWidth();
    final int height = getHeight();
    TabView clonedView = new TabViewBasic(width, height);
    // Transfer information
    int x, y;
    for (x = 0; x < width; x++) {
      for (y = 0; y < height; y++) {
        clonedView.set(x, y, this.getText(x, y), this.getPing(x, y));
      }
    }
    // Done
    return clonedView;
  }

  /**
   * Creates a new clone of this TabView that is of a smaller size than this one.
   *
   * @param newWidth for the tab, smaller than the width of this tab
   * @param newHeight for the tab, smaller than the height of this tab
   * @return cloned tab of the new size
   */
  public TabView cloneResize(int newWidth, int newHeight) {
    if (newWidth > getWidth() || newHeight > getWidth()) {
      throw new IllegalArgumentException("Size {" + newWidth + ", " + newHeight +
          "} is not a sub-size of {" + getWidth() + ", " + getHeight() + "}");
    }
    TabView clonedView = new TabViewBasic(newWidth, newHeight);
    // Transfer information
    int x, y;
    for (x = 0; x < newWidth; x++) {
      for (y = 0; y < newHeight; y++) {
        clonedView.set(x, y, this.getText(x, y), this.getPing(x, y));
      }
    }
    // Done
    return clonedView;
  }

  /**
   * Creates a new Tab View that is a sub-area of this Tab View.
   * Any changes made to this returned Tab View operate on this original Tab View.
   *
   * @param x - coordinate of the top-left start position in this Tab View
   * @param y - coordinate of the top-left start position in this Tab View
   * @param width of the sub-region in this Tab View
   * @param height of the sub-region in this Tab View
   * @return a Tab View instance that is a sub-view of this one
   * @throws IndexOutOfBoundsException if the area specified is not a sub-area of this one
   */
  public TabView subView(int x, int y, int width, int height) {
    boundsCheck(x, y);
    if (x + width > this.getWidth()) {
      throw new IndexOutOfBoundsException("Sub-area is too wide (x{" + x + "} + width{" + width + "} > " + getWidth() + ")");
    }
    if (y + height > this.getHeight()) {
      throw new IndexOutOfBoundsException("Sub-area is too high (x{" + x + "} + width{" + width + "} > " + getWidth() + ")");
    }
    return new TabViewSubView(this, x, y, width, height);
  }

  /**
   * Checks whether a coordinate is part of this Tab View.
   *
   * @param x - coordinate
   * @param y - coordinate
   */
  protected void boundsCheck(int x, int y) {
    if (x < 0 || x > this.getWidth() || y < 0 || y > this.getHeight()) {
      throw new IndexOutOfBoundsException("The coordinate [" + x + ", " + y + "] is out of bounds!");
    }
  }

  /**
   * Gets the index (for a 1-dimensional array) from an x and y coordinate.
   * Also performs a bounds check.
   *
   * @param x - coordinate
   * @param y - coordinate
   * @return 1D-index
   */
  protected int getIndex(int x, int y) {
    boundsCheck(x, y);
    return x + this.getWidth() * y;
  }

  /**
   * Creates a new TabView. This method can only be called
   * while enabling your plugin. Do not call this method while
   * players are joining or logging in - it does NOT work!<br><br>
   *
   * If you need tab instances created at runtime, use clones from one
   * tab created when enabling your plugin. You can use smaller sizes than the
   * original tab, but you can not use larger sizes. You are restricted
   * to defining the maximum tab size you expect to need when enabling.
   *
   * @param width for the new tab
   * @param height for the new tab
   * @return new Tab
   */
  public static TabView createTab(int width, int height) {
    if (CommonUtil.isServerStarted()) {
      throw new IllegalStateException("Can not create new tabs while the server is running, create your tabs while enabling and optionally clone those");
    }
    if (width < 1 || height < 1 || width > MAX_WIDTH || height > MAX_HEIGHT) {
      throw new IllegalArgumentException("Dimension {" + width + ", " + height + "} is outside of the allowed bounds!");
    }
    getController().requestNewSize(width, height);
    return new TabViewBasic(width, height);
  }

  /**
   * Obtains the Tab Controller used to communicate changes to the server
   *
   * @return tab controller
   */
  protected static CommonTabController getController() {
    return CommonPlugin.getInstance().getTabController();
  }
}
TOP

Related Classes of com.bergerkiller.bukkit.common.tab.TabView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.