org.fife.print.RPrintUtilities Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rsyntaxtextarea Show documentation
Show all versions of rsyntaxtextarea Show documentation
RSyntaxTextArea is the syntax highlighting text editor for Swing applications. Features include syntax highlighting for 40+ languages, code folding, code completion, regex find and replace, macros, code templates, undo/redo, line numbering and bracket matching.
/*
* 11/14/2003
*
* RPrintUtilities.java - A collection of static methods useful for printing
* text from Swing text components.
* Copyright (C) 2003 Robert Futrell
* robert_futrell at users.sourceforge.net
* http://fifesoft.com/rsyntaxtextarea
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
package org.fife.print;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.Element;
import javax.swing.text.Segment;
import javax.swing.text.JTextComponent;
import javax.swing.text.TabExpander;
import javax.swing.text.Utilities;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.print.*;
/**
* A collection of static methods useful for printing text from Swing text components.
*
* @author Robert Futrell
* @version 1.0
*/
public abstract class RPrintUtilities {
private static int currentDocLineNumber; // The line number in the document we are currently on.
private static int numDocLines; // The number of lines in the current document.
private static Element rootElement; // The first Element (line) in the current document.
// The characters at which to break a line if implementing word wrap.
private static final char [] breakChars = { ' ', '\t', ',', '.', ';', '?', '!' };
// These variables are 'global' because RPrintTabExpander uses them.
private static int xOffset; // The x-offset (for the page margin) when printing.
private static int tabSizeInSpaces; // The length of a tab, in spaces.
private static FontMetrics fm; // The metrics of the font currently being used to print.
/**
* Returns the position closest to, but before, position maxCharsPerLine
in
* line
of one of the chars in breakChars
, or simply returns
* maxCharsPerLine-1
if none of the breakChars
comes before
* that position. This position represents the logical line break for this java.lang.String
* if it is being printed in a monospaced font when lines can only be maxCharsPerLine
* characters long.
*
* @param line The text being printed.
* @param maxCharsPerLine Only up-to this many characters from
* line
can be printed on one line.
* @return The logical position at which to stop printing line
* to simulate word wrap.
*/
private static int getLineBreakPoint(String line, final int maxCharsPerLine) {
int breakPoint = -1;
for (int i=0; i breakPoint)
breakPoint = breakCharPos;
}
return (breakPoint==-1 ? maxCharsPerLine-1 : breakPoint);
}
/**
* Prints a Document
using a monospaced font, and does no word wrapping (ie,
* words will wrap mid-word to the next line). This method is expected to be called from
* Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param doc The javax.swing.text.Document
to print.
* @param fontSize the point size to use for the monospaced font.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to expand tabs to.
*
* @see #printDocumentMonospacedWordWrap
*/
public static int printDocumentMonospaced(Graphics g, Document doc, int fontSize, int pageIndex,
PageFormat pageFormat, int tabSize) {
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
// Create our tab expander.
//RPrintTabExpander tabExpander = new RPrintTabExpander();
// Get width and height of characters in this monospaced font.
int fontWidth = fm.charWidth('w'); // Any character will do as font is monospaced.
int fontHeight = fm.getHeight();
int MAX_CHARS_PER_LINE = (int)pageFormat.getImageableWidth() / fontWidth;
int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
rootElement = doc.getDefaultRootElement(); // To shorten accesses in our loop.
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
while (currentDocLineNumber -1) {
int spacesNeeded = tabSizeInSpaces - (tabIndex % tabSizeInSpaces);
String replacementString = "";
for (int i=0; i MAX_CHARS_PER_LINE) {
numPrintedLines++;
if (numPrintedLines > STARTING_LINE_NUMBER) {
g.drawString(curLineString.substring(0,MAX_CHARS_PER_LINE), xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
curLineString = curLineString.substring(MAX_CHARS_PER_LINE, curLineString.length());
}
currentDocLineNumber += 1; // We have printed one more line from the document.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
g.drawString(curLineString, xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Prints a Document
using a monospaced font, word wrapping on
* the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
* expected to be called from Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param doc The javax.swing.text.Document
to print.
* @param fontSize the point size to use for the monospaced font.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to expand tabs to.
*
* @see #printDocumentMonospaced
*/
public static int printDocumentMonospacedWordWrap(Graphics g, Document doc,
int fontSize, int pageIndex,
PageFormat pageFormat, int tabSize) {
g.setColor(Color.BLACK);
g.setFont(new Font("Monospaced", Font.PLAIN, fontSize));
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
// Create our tab expander.
//RPrintTabExpander tabExpander = new RPrintTabExpander();
// Get width and height of characters in this monospaced font.
int fontWidth = fm.charWidth('w'); // Any character will do here, since font is monospaced.
int fontHeight = fm.getHeight();
int MAX_CHARS_PER_LINE = (int)pageFormat.getImageableWidth() / fontWidth;
int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
rootElement = doc.getDefaultRootElement(); // To shorten accesses in our loop.
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
while (currentDocLineNumber -1) {
int spacesNeeded = tabSizeInSpaces - (tabIndex % tabSizeInSpaces);
String replacementString = "";
for (int i=0; i MAX_CHARS_PER_LINE) {
int breakPoint = getLineBreakPoint(curLineString, MAX_CHARS_PER_LINE) + 1;
numPrintedLines++;
if (numPrintedLines > STARTING_LINE_NUMBER) {
g.drawString(curLineString.substring(0,breakPoint), xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
curLineString = curLineString.substring(breakPoint, curLineString.length());
}
currentDocLineNumber += 1; // We have printed one more line from the document.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
g.drawString(curLineString, xOffset,y);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Prints a Document
using the specified font, word wrapping
* on the characters ' ', '\t', '\n', ',', '.', and ';'. This method is
* expected to be called from Printable 'print(Graphics g)' functions.
*
* @param g The graphics context to write to.
* @param textComponent The javax.swing.text.JTextComponent
* whose text you're printing.
* @param font The font to use for printing. If null
, then
* textComponent
's font is used.
* @param pageIndex The page number to print.
* @param pageFormat The format to print the page with.
* @param tabSize The number of spaces to convert tabs to.
*
*/
public static int printDocumentWordWrap(Graphics g, JTextComponent textComponent,
Font font, int pageIndex,
PageFormat pageFormat,
int tabSize) {
// Initialize our graphics object.
g.setColor(Color.BLACK);
g.setFont(font!=null ? font : textComponent.getFont());
// Initialize our static variables (these are used by our tab expander below).
tabSizeInSpaces = tabSize;
fm = g.getFontMetrics();
int fontHeight = fm.getHeight();
final int LINE_LENGTH_IN_PIXELS = (int)pageFormat.getImageableWidth();
final int MAX_LINES_PER_PAGE = (int)pageFormat.getImageableHeight() / fontHeight;
final int STARTING_LINE_NUMBER = MAX_LINES_PER_PAGE * pageIndex;
// Create our tab expander.
RPrintTabExpander tabExpander = new RPrintTabExpander();
// The (x,y) coordinate to print at (in pixels, not characters).
// Since y is the baseline of where we'll start printing (not the top-left
// corner), we offset it by the font's ascent ( + 1 just for good measure).
xOffset = (int)pageFormat.getImageableX();
int y = (int)pageFormat.getImageableY() + fm.getAscent() + 1;
// A counter to keep track of the number of lines that WOULD HAVE been
// printed if we were printing all lines.
int numPrintedLines = 0;
// Keep going while there are more lines in the document.
Document doc = textComponent.getDocument();
rootElement = doc.getDefaultRootElement();
numDocLines = rootElement.getElementCount(); // The number of lines in our document.
currentDocLineNumber = 0; // The line number of the document we're currently on.
int startingOffset = 0; // Used when a line is so long it has to be wrapped.
while (currentDocLineNumber LINE_LENGTH_IN_PIXELS) {
//System.err.println("'" + currentLineSeg + "' - " + currentLineLengthInPixels + "/" + LINE_LENGTH_IN_PIXELS);
// Remove any spaces and/or tabs from the end of the segment (would cause problems if you left 'em).
currentLineSeg = removeEndingWhitespace(currentLineSeg);
// currentPos will be the last position in the current text of a "line break character."
currentPos = -1;
String currentLineString = currentLineSeg.toString();
for (int i=0; i-1 && pos>currentPos)
// currentPos = pos;
if (pos>0 && pos>currentPos & pos!=currentLineString.length())
currentPos = pos;
}
// If we didn't find a line break character, we'll simply break the line at
// the last character that fits on a printed line.
// So here, we set currentPos to be the position of the last character that fits
// on the current printed line.
if (currentPos == -1) {
// Fix currentLineSeg so that it contains exactly enough text to fit in
// LINE_LENGTH_IN_PIXELS pixels...
currentPos = 0;
do {
currentPos++;
try {
doc.getText(currentLineStart+startingOffset, currentPos, currentLineSeg);
} catch (BadLocationException ble) {
System.err.println(ble);
return Printable.NO_SUCH_PAGE;
}
currentLineLengthInPixels = Utilities.
getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
} while (currentLineLengthInPixels <= LINE_LENGTH_IN_PIXELS);
currentPos--;
}
try {
doc.getText((currentLineStart+startingOffset), currentPos, currentLineSeg);
} catch (BadLocationException ble) {
System.err.println("BadLocationException in print (a):");
System.err.println("==> currentLineStart: " + currentLineStart +
"; startingOffset: " + startingOffset + "; currentPos: " + currentPos);
System.err.println("==> Range: " + (currentLineStart+startingOffset) + " - " +
(currentLineStart+startingOffset+currentPos));
ble.printStackTrace();
return Printable.NO_SUCH_PAGE;
}
currentLineLengthInPixels = Utilities.getTabbedTextWidth(currentLineSeg, fm, 0, tabExpander, 0);
} // End of while (currentLineLengthInPixels > LINE_LENGTH_IN_PIXELS).
startingOffset += currentPos; // Where to start (offset from line's start), since this line wraps.
} // End of else.
numPrintedLines++;
if (numPrintedLines>STARTING_LINE_NUMBER) {
//g.drawString(currentLineSeg.toString(), xOffset,y);
Utilities.drawTabbedText(currentLineSeg, xOffset,y, g, tabExpander, 0);
y += fontHeight;
if (numPrintedLines==STARTING_LINE_NUMBER+MAX_LINES_PER_PAGE)
return Printable.PAGE_EXISTS;
}
}
// Now, the whole document has been "printed." Decide if this page had any text on it or not.
if (numPrintedLines > STARTING_LINE_NUMBER)
return Printable.PAGE_EXISTS;
return Printable.NO_SUCH_PAGE;
}
/**
* Removes any spaces or tabs from the end of the segment.
*
* @param segment The segment from which to remove tailing whitespace.
* @return segment
with trailing whitespace removed.
*/
private static Segment removeEndingWhitespace(Segment segment) {
int toTrim = 0;
char currentChar = segment.setIndex(segment.getEndIndex()-1);
while ((currentChar==' ' || currentChar=='\t') && currentChar!=Segment.DONE) {
toTrim++;
currentChar = segment.previous();
}
String stringVal = segment.toString();
String newStringVal = stringVal.substring(0,stringVal.length()-toTrim);
return new Segment(newStringVal.toCharArray(), 0, newStringVal.length());
}
/**
* A tab expander for the document currently being printed with the
* font being used for the printing.
*/
private static class RPrintTabExpander implements TabExpander {
RPrintTabExpander() {
}
public float nextTabStop(float x, int tabOffset) {
if (tabSizeInSpaces == 0)
return x;
int tabSizeInPixels = tabSizeInSpaces * fm.charWidth(' ');
int ntabs = (((int) x) - xOffset) / tabSizeInPixels;
return xOffset + ((ntabs + 1) * tabSizeInPixels);
}
}
}