blob: dde15660b866a9ebf68c7e6afcbcc487a37021b9 [file] [log] [blame]
/*******************************************************************************
* Copyright (C) 2007 The University of Manchester
*
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
******************************************************************************/
package net.sf.taverna.t2.lang.ui;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.text.BreakIterator;
import java.util.ArrayList;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
* A JTextArea whose text can be line wrapped either
* based on the size of the scroll pane that holds the text area or by a given
* line width in characters.
*
* @author Alex Nenadic
*
*/
@SuppressWarnings("serial")
public class LineWrappingTextArea extends JTextArea{
String originalText;
String[] wrappedLines;
int lineWidth;
final FontMetrics fontMetrics;
public LineWrappingTextArea(String text){
super(text);
setFont(new Font("Monospaced", Font.PLAIN,12));
fontMetrics = this.getFontMetrics(this.getFont());
setCaretPosition(0);
originalText = text;
}
/**
* Based on:
* @author Robert Hanson
* http://progcookbook.blogspot.com/2006/02/text-wrapping-function-for-java.html
*
* This function takes a string value and a line length, and returns an array of
* lines. Lines are cut on word boundaries, where the word boundary is a space
* character. Spaces are included as the last character of a word, so most lines
* will actually end with a space. This isn't too problematic, but will cause a
* word to wrap if that space pushes it past the max line length.
*
* This is a modified version - added various word boundaries based on Java's word's
* BreakIterator in addition to simply space character as in the original function.
*
*
*/
private String [] wrapTextIntoLines (String text, int len)
{
// BreakIterator will take care of word boundary characters for us
BreakIterator wordIterator = BreakIterator.getWordInstance();
wordIterator.setText(text);
// return empty array for null text
if (text == null)
return new String[] {};
// return text if len is zero or less
if (len <= 0)
return new String[] { text };
// return text if less than length
if (text.length() <= len)
return new String[] { text };
//char[] chars = text.toCharArray(); // no need to copy the text once again
ArrayList<String> lines = new ArrayList<String>();
StringBuffer line = new StringBuffer();
StringBuffer word = new StringBuffer();
for (int i = 0; i < text.length(); i++) {
//for (int i = 0; i < chars.length; i++) {
word.append(text.charAt(i));
//word.append(chars[i]);
if (wordIterator.isBoundary(i)){ // is this character a word boundary?
//if (chars[i] == ' ') {
if ((line.length() + word.length()) > len) {
lines.add(line.toString());
line.delete(0, line.length());
}
line.append(word);
word.delete(0, word.length());
}
}
// handle any extra chars in current word
if (word.length() > 0) {
if ((line.length() + word.length()) > len) {
lines.add(line.toString());
line.delete(0, line.length());
}
line.append(word);
}
// handle extra line
if (line.length() > 0) {
lines.add(line.toString());
}
String[] ret = new String[lines.size()];
int c = 0; // counter
for (String line2 : lines) {
ret[c++] = line2;
}
return ret;
}
public void wrapText() {
// Figure out how many characters to leave in one line
// Based on the size of JTextArea on the screen and font
// size - modified from
// http://www.coderanch.com/t/517006/GUI/java/Visible-column-row-count-JTextArea
// Get width of any char (font is monospaced)
final int charWidth = fontMetrics.charWidth('M');
// Get the width of the visible viewport of the scroll pane
// that contains the lot - loop until such a scroll pane is found
JScrollPane scrollPane = null;
Component currentComponent = getParent();
while (true) {
if (currentComponent == null) {
break;
}
if (currentComponent instanceof JScrollPane) {
scrollPane = (JScrollPane) currentComponent;
break;
} else {
currentComponent = currentComponent.getParent();
}
}
int prefWidth;
int maxChars;
if (scrollPane == null) { // We did not find the parent scroll pane
maxChars = 80; // wrap into lines of 80 characters
} else {
prefWidth = scrollPane.getVisibleRect().width;
// if (scrollPane.getVerticalScrollBar().isVisible()){
// prefWidth = prefWidth - scrollPane.getVerticalScrollBar().getWidth();
// }
maxChars = prefWidth / charWidth - 3; // -3 because there is some
// space between the text
// area and the edge of
// scroll pane so just to be sure
}
// If we have not wrapped lines before or the
// width of the textarea has changed
if (wrappedLines == null || lineWidth != maxChars) {
lineWidth = maxChars;
wrappedLines = wrapTextIntoLines(getText(), lineWidth);
}
if (wrappedLines.length >= 1) {
setText(""); // clear the text area
StringBuffer buff = new StringBuffer();
for (int i = 0; i < wrappedLines.length; i++) {
buff.append(wrappedLines[i] + "\n");
}
// Remove the last \n
setText(buff.substring(0, buff.length()-1));
repaint();
}
}
public void wrapText(int numCharactersPerLine){
// If we have not wrapped lines before or the
// number of characters per line has changed since last
// we wrapped
if (wrappedLines == null || lineWidth != numCharactersPerLine) {
lineWidth = numCharactersPerLine;
wrappedLines = wrapTextIntoLines(getText(), lineWidth);
}
if (wrappedLines.length >= 1) {
setText(""); // clear the text area
for (int i = 0; i < wrappedLines.length; i++) {
append(wrappedLines[i] + "\n");
}
repaint();
}
}
public void unwrapText(){
setText(originalText);
repaint();
}
}