Bukkit  1.4.7-R1.0
 All Classes Namespaces Files Functions Variables Enumerator Pages
ChatPaginator.java
Go to the documentation of this file.
1 package org.bukkit.util;
2 
3 import org.bukkit.ChatColor;
4 
5 import java.util.LinkedList;
6 import java.util.List;
7 
12 public class ChatPaginator {
13  public static final int GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH = 55; // Will never wrap, even with the largest characters
14  public static final int AVERAGE_CHAT_PAGE_WIDTH = 65; // Will typically not wrap using an average character distribution
15  public static final int UNBOUNDED_PAGE_WIDTH = Integer.MAX_VALUE;
16  public static final int OPEN_CHAT_PAGE_HEIGHT = 20; // The height of an expanded chat window
17  public static final int CLOSED_CHAT_PAGE_HEIGHT = 10; // The height of the default chat window
18  public static final int UNBOUNDED_PAGE_HEIGHT = Integer.MAX_VALUE;
19 
26  public static ChatPage paginate(String unpaginatedString, int pageNumber) {
27  return paginate(unpaginatedString, pageNumber, GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH, CLOSED_CHAT_PAGE_HEIGHT);
28  }
29 
38  public static ChatPage paginate(String unpaginatedString, int pageNumber, int lineLength, int pageHeight) {
39  String[] lines = wordWrap(unpaginatedString, lineLength);
40 
41  int totalPages = lines.length / pageHeight + (lines.length % pageHeight == 0 ? 0 : 1);
42  int actualPageNumber = pageNumber <= totalPages ? pageNumber : totalPages;
43 
44  int from = (actualPageNumber - 1) * pageHeight;
45  int to = from + pageHeight <= lines.length ? from + pageHeight : lines.length;
46  String[] selectedLines = Java15Compat.Arrays_copyOfRange(lines, from, to);
47 
48  return new ChatPage(selectedLines, actualPageNumber, totalPages);
49  }
50 
58  public static String[] wordWrap(String rawString, int lineLength) {
59  // A null string is a single line
60  if (rawString == null) {
61  return new String[] {""};
62  }
63 
64  // A string shorter than the lineWidth is a single line
65  if (rawString.length() <= lineLength && !rawString.contains("\n")) {
66  return new String[] {rawString};
67  }
68 
69  char[] rawChars = (rawString + ' ').toCharArray(); // add a trailing space to trigger pagination
70  StringBuilder word = new StringBuilder();
71  StringBuilder line = new StringBuilder();
72  List<String> lines = new LinkedList<String>();
73  int lineColorChars = 0;
74 
75  for (int i = 0; i < rawChars.length; i++) {
76  char c = rawChars[i];
77 
78  // skip chat color modifiers
79  if (c == ChatColor.COLOR_CHAR) {
80  word.append(ChatColor.getByChar(rawChars[i + 1]));
81  lineColorChars += 2;
82  i++; // Eat the next character as we have already processed it
83  continue;
84  }
85 
86  if (c == ' ' || c == '\n') {
87  if (line.length() == 0 && word.length() > lineLength) { // special case: extremely long word begins a line
88  for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
89  lines.add(partialWord);
90  }
91  } else if (line.length() + word.length() - lineColorChars == lineLength) { // Line exactly the correct length...newline
92  line.append(word);
93  lines.add(line.toString());
94  line = new StringBuilder();
95  lineColorChars = 0;
96  } else if (line.length() + 1 + word.length() - lineColorChars > lineLength) { // Line too long...break the line
97  for (String partialWord : word.toString().split("(?<=\\G.{" + lineLength + "})")) {
98  lines.add(line.toString());
99  line = new StringBuilder(partialWord);
100  }
101  lineColorChars = 0;
102  } else {
103  if (line.length() > 0) {
104  line.append(' ');
105  }
106  line.append(word);
107  }
108  word = new StringBuilder();
109 
110  if (c == '\n') { // Newline forces the line to flush
111  lines.add(line.toString());
112  line = new StringBuilder();
113  }
114  } else {
115  word.append(c);
116  }
117  }
118 
119  if(line.length() > 0) { // Only add the last line if there is anything to add
120  lines.add(line.toString());
121  }
122 
123  // Iterate over the wrapped lines, applying the last color from one line to the beginning of the next
124  if (lines.get(0).length() == 0 || lines.get(0).charAt(0) != ChatColor.COLOR_CHAR) {
125  lines.set(0, ChatColor.WHITE + lines.get(0));
126  }
127  for (int i = 1; i < lines.size(); i++) {
128  final String pLine = lines.get(i-1);
129  final String subLine = lines.get(i);
130 
131  char color = pLine.charAt(pLine.lastIndexOf(ChatColor.COLOR_CHAR) + 1);
132  if (subLine.length() == 0 || subLine.charAt(0) != ChatColor.COLOR_CHAR) {
133  lines.set(i, ChatColor.getByChar(color) + subLine);
134  }
135  }
136 
137  return lines.toArray(new String[lines.size()]);
138  }
139 
140  public static class ChatPage {
141 
142  private String[] lines;
143  private int pageNumber;
144  private int totalPages;
145 
146  public ChatPage(String[] lines, int pageNumber, int totalPages) {
147  this.lines = lines;
148  this.pageNumber = pageNumber;
149  this.totalPages = totalPages;
150  }
151 
152  public int getPageNumber() {
153  return pageNumber;
154  }
155 
156  public int getTotalPages() {
157  return totalPages;
158  }
159 
160  public String[] getLines() {
161 
162  return lines;
163  }
164  }
165 }