/******************************************************************************* * Copyright (c) 2001, 2010 Mathew A. Nelson and Robocode contributors * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://robocode.sourceforge.net/license/epl-v10.html * * Contributors: * Mathew A. Nelson * - Initial API and implementation * Flemming N. Larsen * - Code cleanup * Pavel Savara * - number of rows limited *******************************************************************************/ package net.sf.robocode.ui.dialog; import javax.swing.*; import javax.swing.text.DefaultCaret; import java.awt.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; /** * @author Mathew A. Nelson (original) * @author Flemming N. Larsen (contributor) */ @SuppressWarnings("serial") public class ConsoleScrollPane extends JScrollPane { private static final int MAX_ROWS = 500; private static final String TEXT_TRUNCATED_MSG = "^^^ TEXT TRUNCATED ^^^"; private JTextArea textArea; private int lines; private int maxRows; public ConsoleScrollPane() { super(); setViewportView(getTextPane()); } public JTextArea getTextPane() { if (textArea == null) { textArea = new JTextArea(); textArea.setEditable(false); textArea.setTabSize(4); textArea.setBackground(Color.DARK_GRAY); textArea.setForeground(Color.WHITE); textArea.setBounds(0, 0, 1000, 1000); // Make sure the caret is not reset every time text is updated, meaning that // the view will not reset it's position until we want it to. ((DefaultCaret) textArea.getCaret()).setUpdatePolicy(DefaultCaret.NEVER_UPDATE); } return textArea; } public void append(String str) { // Return if the string is null or empty if (str == null || str.length() == 0) { return; } // Append the new string to the text pane getTextPane().append(str); // Count number of new lines, i.e. lines ended with '\n' int numNewLines = str.replaceAll("[^\\n]", "").length(); // Increment the current number of lines with the new lines lines += numNewLines; // Calculate number lines exceeded compared to the max. number of lines int linesExceeded = lines - MAX_ROWS; // Check if we exceeded the number of max. lines if (linesExceeded > 0) { // We use a rolling buffer so that the oldest lines are removed first. // Remove the number of lines we are exceeding in the beginning of the contained text. // Cut down the number of lines to max. number of lines lines = MAX_ROWS; // Find the index where to cut the number of exceeding lines in the beginning of the text String text = getText(); int cutIndex = -1; for (int c = 0; c < linesExceeded; c++) { cutIndex = text.indexOf('\n', cutIndex + 1); } // Replace the first lines of the contained text till the cut index textArea.replaceRange(null, 0, cutIndex + 1); // Replace first line with a message that text has been truncated textArea.replaceRange(TEXT_TRUNCATED_MSG, 0, getText().indexOf('\n')); } // Set the max. number of lines text pane maxRows = Math.max(maxRows, lines); textArea.setRows(maxRows); } public String getSelectedText() { return getTextPane().getSelectedText(); } public String getText() { return getTextPane().getText(); } public void setText(String t) { // Return if the string is null or empty if (t == null || t.length() == 0) { t = null; lines = 0; maxRows = 0; } else { // Calculate and set the new number of lines for the text pane lines = t.replaceAll("[^\\n]", "").length(); // Calculate number lines exceeded compared to the max. number of lines int linesExceeded = lines - MAX_ROWS; // Check if we exceeded the number of max. lines if (linesExceeded > 0) { // We use a rolling buffer so that the oldest lines are removed first. // Remove the number of lines we are exceeding in the beginning of the contained text. // Cut down the number of lines to max. number of lines lines = MAX_ROWS; // Find the index where to cut the number of exceeding lines in the beginning of the text int index = -1; for (int c = 0; c < linesExceeded; c++) { index = t.indexOf('\n', index + 1); } // Replace the first lines of the contained text till the cut index t = t.substring(index + 1); // Replace first line with a message that text has been truncated t = TEXT_TRUNCATED_MSG + t.substring(t.indexOf('\n') + 1); } } // Set the text on the text pane textArea.setText(t); // Set the max. number of lines text pane maxRows = Math.max(maxRows, lines); textArea.setRows(maxRows); } public void processStream(InputStream input) { BufferedReader br = new BufferedReader(new InputStreamReader(input)); String line; try { while ((line = br.readLine()) != null) { append(line + "\n"); } } catch (IOException e) { append("SYSTEM: IOException: " + e); } scrollToBottom(); } public void scrollToBottom() { textArea.setCaretPosition(textArea.getDocument().getLength()); } }