blob: b333851d67d02a6726649421617b79b4d82d2bdb [file] [log] [blame]
package org.eclipse.swt.custom;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved
*/
import java.io.*;
import java.util.Vector;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.custom.*;
import org.eclipse.swt.printing.*;
import org.eclipse.swt.internal.Compatibility;
class StyledTextPrinter implements Runnable {
class RTFState {
int fontStyle;
int foreground;
int background;
}
Vector savedState = new Vector();
Printer printer;
GC gc;
String rtf;
StringBuffer wordBuffer;
int startPage, endPage, currentPage;
int index, end;
String tabs = "";
int tabWidth = 0;
int lineHeight = 0;
int leftMargin, rightMargin, topMargin, bottomMargin;
int x, y;
/* We can optimize for fonts because we know styledText only has one font.
* As soon as we know the font name and point size, we will create and store
* fonts for the following styles: normal, bold, italic, and bold italic.
*/
Font fontTable[][] = new Font[1][4];
boolean creatingFontTable = false;
String fontName;
int fontSize;
int currentFontStyle = SWT.NORMAL;
int currentFont = -1;
int defaultFont = -1;
Vector colorTable = new Vector();
boolean creatingColorTable = false;
int red, green, blue;
int currentForeground = -1;
int currentBackground = -1;
static void print(StyledText styledText) {
Printer printer = new Printer();
new StyledTextPrinter(styledText, printer).run();
printer.dispose();
}
StyledTextPrinter(StyledText styledText, Printer printer) {
this.printer = printer;
PrinterData data = printer.getPrinterData();
startPage = 1;
endPage = Integer.MAX_VALUE;
if (data.scope == PrinterData.PAGE_RANGE) {
startPage = data.startPage;
endPage = data.endPage;
}
/* Create a buffer for computing tab width. */
int tabSize = styledText.getTabs();
StringBuffer tabBuffer = new StringBuffer(tabSize);
for (int i = 0; i < tabSize; i++) tabBuffer.append(' ');
tabs = tabBuffer.toString();
/* Get RTF from the StyledText.*/
rtf = styledText.getRtf();
}
public void run() {
if (printer.startJob("Printing")) {
Rectangle clientArea = printer.getClientArea();
Rectangle trim = printer.computeTrim(0, 0, 0, 0);
Point dpi = printer.getDPI();
leftMargin = dpi.x + trim.x; // one inch from left side of paper
rightMargin = clientArea.width - dpi.x + trim.x + trim.width; // one inch from right side of paper
topMargin = dpi.y + trim.y; // one inch from top edge of paper
bottomMargin = clientArea.height - dpi.y + trim.y + trim.height; // one inch from bottom edge of paper
/* Create a printer GC and print the RTF to it. */
gc = new GC(printer);
x = leftMargin;
y = topMargin;
currentPage = 1;
if (startPage == 1) {
printer.startPage();
}
end = rtf.length();
index = 0;
wordBuffer = new StringBuffer();
while (index < end) {
char c = rtf.charAt(index);
index++;
switch (c) {
case '\\':
printWordBuffer();
parseControlWord();
break;
case '{':
printWordBuffer();
saveState();
break;
case '}':
printWordBuffer();
restoreState();
break;
case 0x0a:
case 0x0d:
printWordBuffer();
break;
default:
parseChar(c);
}
}
if (y + lineHeight <= bottomMargin) {
printer.endPage();
}
printer.endJob();
/* Cleanup */
gc.dispose();
for (int i = 0; i < 4; i++) {
fontTable[currentFont][i].dispose();
}
for (int i = 0; i < colorTable.size(); i++) {
((Color)colorTable.elementAt(i)).dispose();
}
}
}
void parseControlWord() {
if (index >= end) return;
char c = rtf.charAt(index);
index++;
if (!Compatibility.isLetter(c)) {
handleControlSymbol(c);
return;
}
StringBuffer controlWord = new StringBuffer();
controlWord.append(c);
while (index < end) {
c = rtf.charAt(index);
index++;
if (!Compatibility.isLetter(c)) break;
controlWord.append(c);
}
boolean isNegative = false;
if (c == '-') {
isNegative = true;
c = rtf.charAt(index);
index++;
}
boolean hasParameter = false;
StringBuffer paramBuffer = new StringBuffer();
int parameter = 0;
if (Character.isDigit(c)) {
hasParameter = true;
paramBuffer.append(c);
while (index < end) {
c = rtf.charAt(index);
index++;
if (!Character.isDigit(c)) break;
paramBuffer.append(c);
}
try {
parameter = Integer.valueOf(paramBuffer.toString()).intValue();
} catch (NumberFormatException e) {}
if (isNegative) parameter = -parameter;
}
if (c != ' ') index--;
if (hasParameter) {
handleControlWord(controlWord.toString(), parameter);
} else {
handleControlWord(controlWord.toString());
}
}
void parseChar(char c) {
if (c == 0) return;
if (c == ';') {
if (creatingFontTable) {
fontName = wordBuffer.toString();
wordBuffer = new StringBuffer();
creatingFontTable = false;
return;
}
if (creatingColorTable) {
colorTable.addElement(new Color(printer, red, green, blue));
red = green = blue = 0;
return;
}
}
if (c != '\t') {
wordBuffer.append(c);
}
if (!Compatibility.isLetterOrDigit(c) && !creatingFontTable) {
printWordBuffer();
if (c == '\t') {
x += tabWidth;
}
}
}
void printWordBuffer() {
if (wordBuffer.length() > 0) {
String word = wordBuffer.toString();
int wordWidth = gc.stringExtent(word).x;
if (x + wordWidth > rightMargin) {
/* word doesn't fit on current line, so wrap */
newline();
}
if (currentPage >= startPage && currentPage <= endPage) {
gc.drawString(word, x, y, true);
}
x += wordWidth;
wordBuffer = new StringBuffer();
}
}
void handleControlSymbol(char c) {
switch (c) {
case '\\':
case '{':
case '}':
parseChar(c);
}
}
void handleControlWord(String controlWord) {
if (controlWord.equals("par")) newline();
else if (controlWord.equals("b")) setFontStyle(currentFontStyle | SWT.BOLD);
else if (controlWord.equals("i")) setFontStyle(currentFontStyle | SWT.ITALIC);
else if (controlWord.equals("fnil")) setFont(defaultFont);
else if (controlWord.equals("fonttbl")) createFontTable();
else if (controlWord.equals("colortbl")) createColorTable();
}
void handleControlWord(String controlWord, int parameter) {
if (controlWord.equals("highlight")) setBackground(parameter);
else if (controlWord.equals("cf")) setForeground(parameter);
else if (controlWord.equals("b")) setFontStyle(currentFontStyle & ~SWT.BOLD);
else if (controlWord.equals("i")) setFontStyle(currentFontStyle & ~SWT.ITALIC);
else if (controlWord.equals("f")) setFont(parameter);
else if (controlWord.equals("fs")) setFontSize(parameter);
else if (controlWord.equals("red")) red = parameter;
else if (controlWord.equals("green")) green = parameter;
else if (controlWord.equals("blue")) blue = parameter;
else if (controlWord.equals("deff")) setDefaultFont(parameter);
}
void setDefaultFont(int number) {
defaultFont = number;
}
void setFont(int number) {
currentFont = number;
}
void createFontTable() {
creatingFontTable = true;
currentFont = 0;
}
void setFontSize(int size) {
fontSize = size / 2;
createFonts();
}
void createFonts() {
if (fontName != null && fontSize != -1) {
// currentFont must already be set
fontTable[currentFont][0] = new Font(printer, fontName, fontSize, SWT.NORMAL);
fontTable[currentFont][1] = new Font(printer, fontName, fontSize, SWT.BOLD);
fontTable[currentFont][2] = new Font(printer, fontName, fontSize, SWT.ITALIC);
fontTable[currentFont][3] = new Font(printer, fontName, fontSize, SWT.BOLD | SWT.ITALIC);
setFontStyle(SWT.NORMAL);
}
}
void setFontStyle(int style) {
// currentFont must already be set
Font font;
if ((style & SWT.BOLD) != 0) {
if ((style & SWT.ITALIC) != 0) {
font = fontTable[currentFont][3];
} else {
font = fontTable[currentFont][1];
}
} else if ((style & SWT.ITALIC) != 0) {
font = fontTable[currentFont][2];
} else {
font = fontTable[currentFont][0];
}
gc.setFont(font);
tabWidth = gc.stringExtent(tabs).x;
lineHeight = gc.getFontMetrics().getHeight();
currentFontStyle = style;
}
void createColorTable() {
creatingColorTable = true;
red = green = blue = 0;
}
void setForeground(int color) {
if (color != currentForeground) {
// colors must already be in table
gc.setForeground((Color)colorTable.elementAt(color));
currentForeground = color;
}
}
void setBackground(int color) {
if (color != currentBackground) {
// colors must already be in table
gc.setBackground((Color)colorTable.elementAt(color));
currentBackground = color;
}
}
void newline() {
x = leftMargin;
y += lineHeight;
if (y + lineHeight > bottomMargin) {
printer.endPage();
if (index + 1 < end) {
y = topMargin;
currentPage++;
if (currentPage >= startPage && currentPage <= endPage) {
printer.startPage();
}
}
}
}
void saveState() {
RTFState state = new RTFState();
state.fontStyle = currentFontStyle;
state.foreground = currentForeground;
state.background = currentBackground;
savedState.addElement(state);
}
void restoreState() {
if (savedState.isEmpty()) return;
if (creatingColorTable) {
setForeground(0);
setBackground(1);
creatingColorTable = false;
}
int index = savedState.size() - 1;
RTFState state = (RTFState)savedState.elementAt(index);
savedState.removeElementAt(index);
setFontStyle(state.fontStyle);
if (state.foreground != -1) setForeground(state.foreground);
if (state.background != -1) setBackground(state.background);
}
}