Bukkit-API  1.7.9-R0.2
The inofficial Bukkit-API
ChatPaginator.java
1 package org.bukkit.util;
2 
3 import org.bukkit.ChatColor;
4 
5 import java.util.LinkedList;
6 import java.util.List;
7 
8 /**
9  * The ChatPaginator takes a raw string of arbitrary length and breaks it down
10  * into an array of strings appropriate for displaying on the Minecraft player
11  * console.
12  */
13 public class ChatPaginator {
14  public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 55; // Will never wrap, even with the largest characters
15  public static final int AVERAGE_CHAT_PAGE_WIDTH = 65; // Will typically not wrap using an average character distribution
16  public static final int UNBOUNDED_PAGE_WIDTH = Integer.MAX_VALUE;
17  public static final int OPEN_CHAT_PAGE_HEIGHT = 20; // The height of an expanded chat window
18  public static final int CLOSED_CHAT_PAGE_HEIGHT = 10; // The height of the default chat window
19  public static final int UNBOUNDED_PAGE_HEIGHT = Integer.MAX_VALUE;
20 
21  /**
22  * Breaks a raw string up into pages using the default width and height.
23  *
24  * @param unpaginatedString The raw string to break.
25  * @param pageNumber The page number to fetch.
26  * @return A single chat page.
27  */
28  public static ChatPage paginate(String unpaginatedString, int pageNumber) {
29  return paginate(unpaginatedString, pageNumber, GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH, CLOSED_CHAT_PAGE_HEIGHT);
30  }
31 
32  /**
33  * Breaks a raw string up into pages using a provided width and height.
34  *
35  * @param unpaginatedString The raw string to break.
36  * @param pageNumber The page number to fetch.
37  * @param lineLength The desired width of a chat line.
38  * @param pageHeight The desired number of lines in a page.
39  * @return A single chat page.
40  */
41  public static ChatPage paginate(String unpaginatedString, int pageNumber, int lineLength, int pageHeight) {
42  String[] lines = wordWrap(unpaginatedString, lineLength);
43 
44  int totalPages = lines.length / pageHeight + (lines.length % pageHeight == 0 ? 0 : 1);
45  int actualPageNumber = pageNumber <= totalPages ? pageNumber : totalPages;
46 
47  int from = (actualPageNumber - 1) * pageHeight;
48  int to = from + pageHeight <= lines.length ? from + pageHeight : lines.length;
49  String[] selectedLines = Java15Compat.Arrays_copyOfRange(lines, from, to);
50 
51  return new ChatPage(selectedLines, actualPageNumber, totalPages);
52  }
53 
54  /**
55  * Breaks a raw string up into a series of lines. Words are wrapped using
56  * spaces as decimeters and the newline character is respected.
57  *
58  * @param rawString The raw string to break.
59  * @param lineLength The length of a line of text.
60  * @return An array of word-wrapped lines.
61  */
62  public static String[] wordWrap(String rawString, int lineLength) {
63  // A null string is a single line
64  if (rawString == null) {
65  return new String[] {""};
66  }
67 
68  // A string shorter than the lineWidth is a single line
69  if (rawString.length() <= lineLength && !rawString.contains("\n")) {
70  return new String[] {rawString};
71  }
72 
73  char[] rawChars = (rawString + ' ').toCharArray(); // add a trailing space to trigger pagination
74  StringBuilder word = new StringBuilder();
75  StringBuilder line = new StringBuilder();
76  List<String> lines = new LinkedList<String>();
77  int lineColorChars = 0;
78 
79  for (int i = 0; i < rawChars.length; i++) {
80  char c = rawChars[i];
81 
82  // skip chat color modifiers
83  if (c == ChatColor.COLOR_CHAR) {
84  word.append(ChatColor.getByChar(rawChars[i + 1]));
85  lineColorChars += 2;
86  i++; // Eat the next character as we have already processed it
87  continue;
88  }
89 
90  if (c == ' ' || c == '\n') {
91  if (line.length() == 0 && word.length() > lineLength) { // special case: extremely long word begins a line
92  for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
93  lines.add(partialWord);
94  }
95  } else if (line.length() + word.length() - lineColorChars == lineLength) { // Line exactly the correct length...newline
96  line.append(word);
97  lines.add(line.toString());
98  line = new StringBuilder();
99  lineColorChars = 0;
100  } else if (line.length() + 1 + word.length() - lineColorChars > lineLength) { // Line too long...break the line
101  for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
102  lines.add(line.toString());
103  line = new StringBuilder(partialWord);
104  }
105  lineColorChars = 0;
106  } else {
107  if (line.length() > 0) {
108  line.append(' ');
109  }
110  line.append(word);
111  }
112  word = new StringBuilder();
113 
114  if (c == '\n') { // Newline forces the line to flush
115  lines.add(line.toString());
116  line = new StringBuilder();
117  }
118  } else {
119  word.append(c);
120  }
121  }
122 
123  if(line.length() > 0) { // Only add the last line if there is anything to add
124  lines.add(line.toString());
125  }
126 
127  // Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
128  if (lines.get(0).length() == 0 || lines.get(0).charAt(0) != ChatColor.COLOR_CHAR) {
129  lines.set(0, ChatColor.WHITE + lines.get(0));
130  }
131  for (int i = 1; i < lines.size(); i++) {
132  final String pLine = lines.get(i-1);
133  final String subLine = lines.get(i);
134 
135  char color = pLine.charAt(pLine.lastIndexOf(ChatColor.COLOR_CHAR) + 1);
136  if (subLine.length() == 0 || subLine.charAt(0) != ChatColor.COLOR_CHAR) {
137  lines.set(i, ChatColor.getByChar(color) + subLine);
138  }
139  }
140 
141  return lines.toArray(new String[lines.size()]);
142  }
143 
144  public static class ChatPage {
145 
146  private String[] lines;
147  private int pageNumber;
148  private int totalPages;
149 
150  public ChatPage(String[] lines, int pageNumber, int totalPages) {
151  this.lines = lines;
152  this.pageNumber = pageNumber;
153  this.totalPages = totalPages;
154  }
155 
156  public int getPageNumber() {
157  return pageNumber;
158  }
159 
160  public int getTotalPages() {
161  return totalPages;
162  }
163 
164  public String[] getLines() {
165 
166  return lines;
167  }
168  }
169 }
static ChatColor getByChar(char code)
Definition: ChatColor.java:163
static String[] wordWrap(String rawString, int lineLength)
static ChatPage paginate(String unpaginatedString, int pageNumber, int lineLength, int pageHeight)
staticfinal char COLOR_CHAR
Definition: ChatColor.java:107
static ChatPage paginate(String unpaginatedString, int pageNumber)