Use HTML to print

Allows multiple tabs at once and lifts responsibility for print
rendering from TextAreaPainter.

Fixes #50, closes #213.
This commit is contained in:
George Bateman
2016-03-23 18:33:36 +00:00
parent b3da867769
commit c3b35773cd
3 changed files with 81 additions and 79 deletions

View File

@@ -258,11 +258,6 @@ public class JEditTextArea extends JComponent
}
public final Printable getPrintable() {
return painter.getPrintable();
}
/**
* Returns the input handler.
*/
@@ -1724,7 +1719,25 @@ public class JEditTextArea extends JComponent
* specific to any language or version of the PDE.
*/
public void copyAsHTML() {
StringBuilder cf = new StringBuilder("<html><body><pre>\n");
HtmlSelection formatted = new HtmlSelection("<html><body><pre>\n"
+ getTextAsHtml(null) + "\n</pre></body></html>");
Clipboard clipboard = processing.app.ui.Toolkit.getSystemClipboard();
clipboard.setContents(formatted, new ClipboardOwner() {
public void lostOwnership(Clipboard clipboard, Transferable contents) {
// I don't care about ownership
}
});
}
/**
* Guts of copyAsHTML, minus the pre, body, and html blocks surrounding.
* @param doc If null, read only the selection if any, and use the active
* document. Otherwise, the whole of doc is used.
*/
public String getTextAsHtml(SyntaxDocument doc) {
StringBuilder cf = new StringBuilder();
int selStart = getSelectionStart();
int selStop = getSelectionStop();
@@ -1732,8 +1745,12 @@ public class JEditTextArea extends JComponent
int startLine = getSelectionStartLine();
int stopLine = getSelectionStopLine();
if (doc != null) {
startLine = 0;
stopLine = doc.getDefaultRootElement().getElementCount() - 1;
}
// If no selection, convert all the lines
if (selStart == selStop) {
else if (selStart == selStop) {
startLine = 0;
stopLine = getLineCount() - 1;
} else {
@@ -1742,55 +1759,45 @@ public class JEditTextArea extends JComponent
stopLine--;
}
}
if (doc == null) {
doc = getDocument();
}
// Read the code line by line
for (int i = startLine; i <= stopLine; i++) {
emitAsHTML(cf, i);
emitAsHTML(cf, i, doc);
}
cf.append("\n</pre></body></html>");
HtmlSelection formatted = new HtmlSelection(cf.toString());
Clipboard clipboard = processing.app.ui.Toolkit.getSystemClipboard();
clipboard.setContents(formatted, new ClipboardOwner() {
public void lostOwnership(Clipboard clipboard, Transferable contents) {
// i don't care about ownership
}
});
return cf.toString();
}
private void emitAsHTML(StringBuilder cf, int line) {
private void emitAsHTML(StringBuilder cf, int line, SyntaxDocument doc) {
// Almost static; only needs the painter for a color scheme.
Segment segment = new Segment();
getLineText(line, segment);
try {
Element element = doc.getDefaultRootElement().getElement(line);
int start = element.getStartOffset();
int stop = element.getEndOffset();
doc.getText(start, stop - start - 1, segment);
} catch (BadLocationException e) { return; }
char[] segmentArray = segment.array;
int limit = segment.getEndIndex();
int segmentOffset = segment.offset;
int segmentCount = segment.count;
TokenMarker tokenMarker = getTokenMarker();
TokenMarker tokenMarker = doc.getTokenMarker();
// If syntax coloring is disabled, do simple translation
if (tokenMarker == null) {
for (int j = 0; j < segmentCount; j++) {
char c = segmentArray[j + segmentOffset];
//cf = cf.append(c);
appendAsHTML(cf, c);
}
} else {
// If syntax coloring is enabled, we have to do this
// because tokens can vary in width
Token tokens;
if ((painter.getCurrentLineIndex() == line) &&
(painter.getCurrentLineTokens() != null)) {
tokens = painter.getCurrentLineTokens();
} else {
painter.setCurrentLineIndex(line);
painter.setCurrentLineTokens(tokenMarker.markTokens(segment, line));
tokens = painter.getCurrentLineTokens();
}
Token tokens = tokenMarker.markTokens(segment, line);
int offset = 0;
SyntaxStyle[] styles = painter.getStyles();
@@ -1798,10 +1805,8 @@ public class JEditTextArea extends JComponent
for (;;) {
byte id = tokens.id;
if (id == Token.END) {
char c = segmentArray[segmentOffset + offset];
if (segmentOffset + offset < limit) {
//cf.append(c);
appendAsHTML(cf, c);
appendAsHTML(cf, segmentArray[segmentOffset + offset]);
} else {
cf.append('\n');
}
@@ -1824,7 +1829,6 @@ public class JEditTextArea extends JComponent
cf.append("&nbsp;");
} else {
appendAsHTML(cf, c);
//cf.append(c);
}
// Place close tags [/]
if (j == (length - 1) && id != Token.NULL && styles[id].isBold())

View File

@@ -12,7 +12,6 @@ package processing.app.syntax;
import java.awt.event.MouseEvent;
import java.awt.*;
import java.awt.print.*;
import javax.swing.ToolTipManager;
import javax.swing.text.*;
@@ -28,9 +27,6 @@ import processing.app.syntax.im.CompositionTextPainter;
* @author Slava Pestov
*/
public class TextAreaPainter extends JComponent implements TabExpander {
/** True if inside printing, will handle disabling the highlight */
boolean printing;
/** A specific painter composed by the InputMethod.*/
protected CompositionTextPainter compositionTextPainter;
@@ -502,38 +498,6 @@ public class TextAreaPainter extends JComponent implements TabExpander {
}
public Printable getPrintable() {
return new Printable() {
@Override
public int print(Graphics graphics, PageFormat pageFormat,
int pageIndex) throws PrinterException {
int lineHeight = fm.getHeight();
int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
int lineCount = textArea.getLineCount();
int lastPage = lineCount / linesPerPage;
if (pageIndex > lastPage) {
return NO_SUCH_PAGE;
} else {
Graphics2D g2 = (Graphics2D) graphics;
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
int firstLine = pageIndex*linesPerPage;
g2.translate(Math.max(54, pageFormat.getImageableX()),
pageFormat.getImageableY() - firstLine*lineHeight);
printing = true;
for (int line = firstLine; line < firstLine + linesPerPage; line++) {
paintLine(g2, line, 0, tokenMarker);
}
printing = false;
return PAGE_EXISTS;
}
}
};
}
/**
* Marks a line as needing a repaint.
* @param line The line to invalidate
@@ -661,9 +625,7 @@ public class TextAreaPainter extends JComponent implements TabExpander {
// protected void paintPlainLine(Graphics gfx, int line, Font defaultFont,
// Color defaultColor, int x, int y) {
protected void paintPlainLine(Graphics gfx, int line, int x, int y) {
if (!printing) {
paintHighlight(gfx,line,y);
}
paintHighlight(gfx,line,y);
textArea.getLineText(line, currentLine);
// gfx.setFont(plainFont);
@@ -786,8 +748,7 @@ public class TextAreaPainter extends JComponent implements TabExpander {
}
protected void paintHighlight(Graphics gfx, int line, int y) {//, boolean printing) {
// if (!printing) {
protected void paintHighlight(Graphics gfx, int line, int y) {
if (line >= textArea.getSelectionStartLine() &&
line <= textArea.getSelectionStopLine()) {
paintLineHighlight(gfx, line, y);

View File

@@ -64,6 +64,7 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.plaf.basic.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
import javax.swing.undo.*;
@@ -2610,15 +2611,51 @@ public abstract class Editor extends JFrame implements RunnerListener {
*/
public void handlePrint() {
statusNotice(Language.text("editor.status.printing"));
StringBuilder html = new StringBuilder("<html><body>");
for (SketchCode tab : sketch.getCode()) {
html.append("<b>" + tab.getPrettyName() + "</b><br>");
html.append(textarea.getTextAsHtml((SyntaxDocument)tab.getDocument()));
html.append("<br>");
}
html.setLength(html.length() - 4); // Don't want last <br>.
html.append("</body></html>");
JTextPane jtp = new JTextPane();
// Needed for good line wrapping; otherwise one very long word breaks
// wrapping for the whole document.
jtp.setEditorKit(new HTMLEditorKit() {
public ViewFactory getViewFactory() {
return new HTMLFactory() {
public View create(Element e) {
View v = super.create(e);
if (!(v instanceof javax.swing.text.html.ParagraphView))
return v;
else
return new javax.swing.text.html.ParagraphView(e) {
protected SizeRequirements calculateMinorAxisRequirements(
int axis, SizeRequirements r) {
r = super.calculateMinorAxisRequirements(axis, r);
r.minimum = 1;
return r;
}
};
}
};
}
});
jtp.setFont(new Font(Preferences.get("editor.font.family"), Font.PLAIN, 10));
jtp.setText(html.toString().replace("\n", "<br>") // Not in a <pre>.
.replaceAll("(?<!&nbsp;)&nbsp;", " ")); // Allow line wrap.
//printerJob = null;
if (printerJob == null) {
printerJob = PrinterJob.getPrinterJob();
}
if (pageFormat != null) {
//System.out.println("setting page format " + pageFormat);
printerJob.setPrintable(textarea.getPrintable(), pageFormat);
printerJob.setPrintable(jtp.getPrintable(null, null), pageFormat);
} else {
printerJob.setPrintable(textarea.getPrintable());
printerJob.setPrintable(jtp.getPrintable(null, null));
}
// set the name of the job to the code name
printerJob.setJobName(sketch.getCurrentCode().getPrettyName());