mirror of
https://github.com/processing/processing4.git
synced 2026-02-14 10:55:38 +01:00
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:
@@ -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(" ");
|
||||
} else {
|
||||
appendAsHTML(cf, c);
|
||||
//cf.append(c);
|
||||
}
|
||||
// Place close tags [/]
|
||||
if (j == (length - 1) && id != Token.NULL && styles[id].isBold())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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("(?<! ) ", " ")); // 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());
|
||||
|
||||
Reference in New Issue
Block a user