IDEA-122718 New print keywords

This commit is contained in:
Dmitry Batrak
2014-12-26 12:37:42 +03:00
parent 2a05f9d072
commit 71bf1a276b
3 changed files with 178 additions and 78 deletions
@@ -114,26 +114,8 @@ class PrintManager {
painter = new MultiFilePainter(filesList);
}
Pageable document = new Pageable() {
@Override
public int getNumberOfPages() {
return Pageable.UNKNOWN_NUMBER_OF_PAGES;
}
@Override
public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
return pageFormat;
}
@Override
public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
return painter;
}
};
final PrinterJob printerJob = PrinterJob.getPrinterJob();
try {
printerJob.setPageable(document);
printerJob.setPrintable(painter, pageFormat);
if (!printerJob.printDialog()) {
return;
@@ -230,7 +212,8 @@ class PrintManager {
if (doc == null) return null;
EditorHighlighter highlighter = HighlighterFactory.createHighlighter(psiFile.getProject(), virtualFile);
highlighter.setText(doc.getCharsSequence());
return new TextPainter(doc, highlighter, virtualFile.getPresentableUrl(), psiFile, psiFile.getFileType(), editor);
return new TextPainter(doc, highlighter, virtualFile.getPresentableUrl(), virtualFile.getPresentableName(),
psiFile, psiFile.getFileType(), editor);
}
private static TextPainter initTextPainter(@NotNull final DocumentEx doc, final Project project) {
@@ -249,6 +232,6 @@ class PrintManager {
private static TextPainter doInitTextPainter(@NotNull final DocumentEx doc, Project project) {
EditorHighlighter highlighter = HighlighterFactory.createHighlighter(project, "unknown");
highlighter.setText(doc.getCharsSequence());
return new TextPainter(doc, highlighter, "unknown", project, FileTypes.PLAIN_TEXT, null);
return new TextPainter(doc, highlighter, "unknown", "unknown", project, FileTypes.PLAIN_TEXT, null);
}
}
@@ -28,6 +28,7 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
@@ -45,6 +46,8 @@ import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
class TextPainter extends BasePainter {
@@ -62,32 +65,48 @@ class TextPainter extends BasePainter {
private final Font myHeaderFont;
private final EditorHighlighter myHighlighter;
private final PrintSettings myPrintSettings;
private final String myFileName;
private final String myFullFileName;
private final String myShortFileName;
private int myPageIndex;
private int myNumberOfPages = -1;
private int mySegmentEnd;
private final LineMarkerInfo[] myMethodSeparators;
private int myCurrentMethodSeparator;
private final CodeStyleSettings myCodeStyleSettings;
private final FileType myFileType;
private boolean myPerformActualDrawing;
private final String myPrintDate;
private final String myPrintTime;
@NonNls private static final String DEFAULT_MEASURE_HEIGHT_TEXT = "A";
@NonNls private static final String DEFAULT_MEASURE_WIDTH_TEXT = "w";
@NonNls private static final String HEADER_TOKEN_PAGE = "PAGE";
@NonNls private static final String HEADER_TOKEN_TOTALPAGES = "TOTALPAGES";
@NonNls private static final String HEADER_TOKEN_FILE = "FILE";
@NonNls private static final String HEADER_TOKEN_FILENAME = "FILENAME";
@NonNls private static final String HEADER_TOKEN_DATE = "DATE";
@NonNls private static final String HEADER_TOKEN_TIME = "TIME";
@NonNls private static final String DATE_FORMAT = "yyyy-MM-dd";
@NonNls private static final String TIME_FORMAT = "HH:mm:ss";
public TextPainter(@NotNull DocumentEx editorDocument,
EditorHighlighter highlighter,
String fileName,
String fullFileName,
String shortFileName,
@NotNull PsiFile psiFile,
FileType fileType,
Editor editor) {
this(editorDocument, highlighter, fileName, psiFile.getProject(), fileType,
this(editorDocument, highlighter, fullFileName, shortFileName, psiFile.getProject(), fileType,
FileSeparatorProvider.getInstance().getFileSeparators(psiFile, editorDocument, editor));
}
public TextPainter(@NotNull DocumentEx editorDocument,
EditorHighlighter highlighter,
String fileName,
String fullFileName,
String shortFileName,
Project project,
FileType fileType,
List<LineMarkerInfo> separators) {
@@ -102,18 +121,26 @@ class TextPainter extends BasePainter {
myBoldItalicFont = new Font(fontName, Font.BOLD | Font.ITALIC, fontSize);
myHighlighter = highlighter;
myHeaderFont = new Font(myPrintSettings.FOOTER_HEADER_FONT_NAME, Font.PLAIN, myPrintSettings.FOOTER_HEADER_FONT_SIZE);
myFileName = fileName;
myFullFileName = fullFileName;
myShortFileName = shortFileName;
myRangeToPrint = editorDocument.createRangeMarker(0, myDocument.getTextLength());
myFileType = fileType;
myMethodSeparators = separators != null ? separators.toArray(new LineMarkerInfo[separators.size()]) : new LineMarkerInfo[0];
myCurrentMethodSeparator = 0;
Date date = new Date();
myPrintDate = new SimpleDateFormat(DATE_FORMAT).format(date);
myPrintTime = new SimpleDateFormat(TIME_FORMAT).format(date);
}
public void setSegment(int segmentStart, int segmentEnd) {
setSegment(myDocument.createRangeMarker(segmentStart, segmentEnd));
}
private void setSegment(RangeMarker marker) {
if (myRangeToPrint != null) {
myRangeToPrint.dispose();
}
myRangeToPrint = myDocument.createRangeMarker(segmentStart, segmentEnd);
myRangeToPrint = marker;
}
private float getLineHeight(Graphics g) {
@@ -151,42 +178,104 @@ class TextPainter extends BasePainter {
@Override
public int print(final Graphics g, final PageFormat pageFormat, final int pageIndex) throws PrinterException {
if (myProgress.isCanceled()) {
return NO_SUCH_PAGE;
}
final Graphics2D g2d = (Graphics2D)g;
if (myNumberOfPages < 0) {
myProgress.setText(CodeEditorBundle.message("print.file.calculating.number.of.pages.progress"));
myPerformActualDrawing = false;
if (!calculateNumberOfPages(g2d, pageFormat)) {
return NO_SUCH_PAGE;
}
}
myPerformActualDrawing = true;
return ApplicationManager.getApplication().runReadAction(new Computable<Integer>() {
@Override
public Integer compute() {
if (myProgress.isCanceled() || myRangeToPrint == null || !myRangeToPrint.isValid()) {
if (!isValidRange(myRangeToPrint)) {
return NO_SUCH_PAGE;
}
int startOffset = myRangeToPrint.getStartOffset();
myOffset = startOffset;
mySegmentEnd = myRangeToPrint.getEndOffset();
myLineNumber = myDocument.getLineNumber(myOffset) + 1;
if (myOffset >= mySegmentEnd) {
return NO_SUCH_PAGE;
}
isPrintingPass = !isPrintingPass;
if (!isPrintingPass) {
return PAGE_EXISTS;
}
myProgress.setText(CodeEditorBundle.message("print.file.page.progress", myFileName, (pageIndex + 1)));
myProgress.setText(CodeEditorBundle.message("print.file.page.progress", myShortFileName, (pageIndex + 1), myNumberOfPages));
myPageIndex = pageIndex;
Graphics2D g2D = (Graphics2D) g;
Rectangle2D.Double clip = new Rectangle2D.Double(pageFormat.getImageableX(), pageFormat.getImageableY(),
pageFormat.getImageableWidth(),
pageFormat.getImageableHeight());
draw(g2D, clip);
RangeMarker newRange = printPage(g2d, pageFormat, myRangeToPrint);
setSegment(newRange);
myRangeToPrint.dispose();
// stop printing if there was no progress (to avoid an infinite loop) or if the whole range was processed
myRangeToPrint = myOffset > startOffset && myOffset < mySegmentEnd ? myDocument.createRangeMarker(myOffset, mySegmentEnd) : null;
return PAGE_EXISTS;
}
});
}
private boolean calculateNumberOfPages(final Graphics2D g2d, final PageFormat pageFormat) {
myNumberOfPages = 0;
final Ref<Boolean> firstPage = new Ref<Boolean>(Boolean.TRUE);
final Ref<RangeMarker> tmpMarker = new Ref<RangeMarker>();
while (ApplicationManager.getApplication().runReadAction(new Computable<Boolean>() {
@Override
public Boolean compute() {
if (firstPage.get()) {
if (!isValidRange(myRangeToPrint)) {
return false;
}
tmpMarker.set(myDocument.createRangeMarker(myRangeToPrint.getStartOffset(), myRangeToPrint.getEndOffset()));
firstPage.set(Boolean.FALSE);
}
RangeMarker range = tmpMarker.get();
if (!isValidRange(range)) {
return false;
}
tmpMarker.set(printPage(g2d, pageFormat, range));
range.dispose();
return true;
}
})) {
if (myProgress.isCanceled()) {
return false;
}
myNumberOfPages++;
}
if (!tmpMarker.isNull()) {
tmpMarker.get().dispose();
}
return true;
}
private static boolean isValidRange(RangeMarker range) {
return range != null && range.isValid() && range.getStartOffset() < range.getEndOffset();
}
/**
* Prints a pageful of text from a given range. Return a remaining range to print, or null if there's nothing left.
*/
private RangeMarker printPage(Graphics2D g2d, PageFormat pageFormat, RangeMarker range) {
assert isValidRange(range);
int startOffset = range.getStartOffset();
int endOffset = range.getEndOffset();
myOffset = startOffset;
mySegmentEnd = endOffset;
myLineNumber = myDocument.getLineNumber(myOffset) + 1;
Rectangle2D.Double clip = new Rectangle2D.Double(pageFormat.getImageableX(), pageFormat.getImageableY(),
pageFormat.getImageableWidth(), pageFormat.getImageableHeight());
draw(g2d, clip);
return myOffset > startOffset && myOffset < endOffset ? myDocument.createRangeMarker(myOffset, endOffset) : null;
}
private void draw(Graphics2D g2D, Rectangle2D.Double clip) {
double headerHeight = drawHeader(g2D, clip);
clip.y += headerHeight;
@@ -209,7 +298,7 @@ class TextPainter extends BasePainter {
}
private void drawBorder(Graphics2D g, Rectangle2D clip) {
if (myPrintSettings.DRAW_BORDER) {
if (myPrintSettings.DRAW_BORDER && myPerformActualDrawing) {
Color save = g.getColor();
g.setColor(Color.black);
g.draw(clip);
@@ -270,10 +359,8 @@ class TextPainter extends BasePainter {
Point2D position = new Point2D.Double(0, clip.getY());
double lineY = position.getY();
while (myCurrentMethodSeparator < myMethodSeparators.length) {
LineMarkerInfo marker = myMethodSeparators[myCurrentMethodSeparator];
if (marker != null && marker.startOffset >= lIterator.getEnd()) break;
myCurrentMethodSeparator++;
if (myPerformActualDrawing) {
setInitialMethodSeparatorIndex(lIterator.getEnd());
}
while (!hIterator.atEnd() && !lIterator.atEnd()) {
@@ -290,14 +377,13 @@ class TextPainter extends BasePainter {
lIterator.advance();
myLineNumber++;
if (myCurrentMethodSeparator < myMethodSeparators.length) {
LineMarkerInfo marker = myMethodSeparators[myCurrentMethodSeparator];
if (marker != null && marker.startOffset < lEnd) {
if (myPerformActualDrawing) {
LineMarkerInfo marker = getMethodSeparator(lEnd);
if (marker != null) {
Color save = g.getColor();
setForegroundColor(g, marker.separatorColor);
UIUtil.drawLine(g, 0, (int)lineY, (int)clip.getWidth(), (int)lineY);
setForegroundColor(g, save);
myCurrentMethodSeparator++;
}
}
@@ -343,6 +429,25 @@ class TextPainter extends BasePainter {
g.translate(-clip.getX(), 0);
}
private void setInitialMethodSeparatorIndex(int initialOffset) {
while (myCurrentMethodSeparator < myMethodSeparators.length) {
LineMarkerInfo marker = myMethodSeparators[myCurrentMethodSeparator];
if (marker != null && marker.startOffset >= initialOffset) break;
myCurrentMethodSeparator++;
}
}
private LineMarkerInfo getMethodSeparator(int currentOffset) {
if (myCurrentMethodSeparator < myMethodSeparators.length) {
LineMarkerInfo marker = myMethodSeparators[myCurrentMethodSeparator];
if (marker != null && marker.startOffset < currentOffset) {
myCurrentMethodSeparator++;
return marker;
}
}
return null;
}
private double drawHeader(Graphics2D g, Rectangle2D clip) {
LineMetrics lineMetrics = getHeaderFooterLineMetrics(g);
@@ -407,21 +512,23 @@ class TextPainter extends BasePainter {
private double drawHeaderOrFooterLine(Graphics2D g, double x, double y, double w, String headerText,
String alignment) {
headerText = convertHeaderText(headerText);
g.setFont(myHeaderFont);
g.setColor(Color.black);
FontRenderContext fontRenderContext = g.getFontRenderContext();
LineMetrics lineMetrics = getHeaderFooterLineMetrics(g);
float lineHeight = lineMetrics.getHeight();
float descent = lineMetrics.getDescent();
double width = myHeaderFont.getStringBounds(headerText, fontRenderContext).getWidth() + getCharWidth(g);
float yPos = (float) (lineHeight - descent + y);
if (PrintSettings.LEFT.equals(alignment)) {
drawStringToGraphics(g, headerText, x, yPos);
} else if (PrintSettings.CENTER.equals(alignment)) {
drawStringToGraphics(g, headerText, (float) (x + (w - width) / 2), yPos);
} else if (PrintSettings.RIGHT.equals(alignment)) {
drawStringToGraphics(g, headerText, (float) (x + w - width), yPos);
if (myPerformActualDrawing) {
headerText = convertHeaderText(headerText);
g.setFont(myHeaderFont);
g.setColor(Color.black);
float descent = lineMetrics.getDescent();
double width = myHeaderFont.getStringBounds(headerText, fontRenderContext).getWidth() + getCharWidth(g);
float yPos = (float) (lineHeight - descent + y);
if (PrintSettings.LEFT.equals(alignment)) {
drawStringToGraphics(g, headerText, x, yPos);
} else if (PrintSettings.CENTER.equals(alignment)) {
drawStringToGraphics(g, headerText, (float) (x + (w - width) / 2), yPos);
} else if (PrintSettings.RIGHT.equals(alignment)) {
drawStringToGraphics(g, headerText, (float) (x + w - width), yPos);
}
}
return lineHeight;
}
@@ -437,8 +544,16 @@ class TextPainter extends BasePainter {
if (isExpression) {
if (HEADER_TOKEN_PAGE.equals(token)) {
result.append(myPageIndex + 1);
} else if (HEADER_TOKEN_TOTALPAGES.equals(token)) {
result.append(myNumberOfPages);
} else if (HEADER_TOKEN_FILE.equals(token)) {
result.append(myFileName);
result.append(myFullFileName);
} else if (HEADER_TOKEN_FILENAME.equals(token)) {
result.append(myShortFileName);
} else if (HEADER_TOKEN_DATE.equals(token)) {
result.append(myPrintDate);
} else if (HEADER_TOKEN_TIME.equals(token)) {
result.append(myPrintTime);
}
} else {
result.append(token);
@@ -475,7 +590,7 @@ class TextPainter extends BasePainter {
}
private void drawLineNumber(Graphics2D g, double x, double y) {
if (!myPrintSettings.PRINT_LINE_NUMBERS) {
if (!myPrintSettings.PRINT_LINE_NUMBERS || !myPerformActualDrawing) {
return;
}
FontRenderContext fontRenderContext = (g).getFontRenderContext();
@@ -538,7 +653,7 @@ class TextPainter extends BasePainter {
double xStart = position.getX();
double x = position.getX();
double y = getLineHeight(g) - getDescent(g) + position.getY();
if (backColor != null) {
if (backColor != null && myPerformActualDrawing) {
Color savedColor = g.getColor();
setBackgroundColor(g, backColor);
double w = getTextSegmentWidth(text, myOffset, length, position.getX(), g);
@@ -567,7 +682,7 @@ class TextPainter extends BasePainter {
x += drawStringToGraphics(g, s, x, y);
}
if (underscoredColor != null) {
if (underscoredColor != null && myPerformActualDrawing) {
Color savedColor = g.getColor();
setForegroundColor(g, underscoredColor);
double w = getTextSegmentWidth(text, myOffset, length, position.getX(), g);
@@ -581,13 +696,17 @@ class TextPainter extends BasePainter {
private double drawStringToGraphics(Graphics2D g, String s, double x, double y) {
if (!myPrintSettings.PRINT_AS_GRAPHICS) {
g.drawString(s, (float) x, (float) y);
if (myPerformActualDrawing) {
g.drawString(s, (float)x, (float)y);
}
return g.getFontMetrics().stringWidth(s);
} else {
GlyphVector v = g.getFont().createGlyphVector(g.getFontRenderContext(), s);
g.translate(x, y);
g.fill(v.getOutline());
g.translate(-x, -y);
if (myPerformActualDrawing) {
g.translate(x, y);
g.fill(v.getOutline());
g.translate(-x, -y);
}
return v.getLogicalBounds().getWidth();
}
@@ -635,9 +754,6 @@ class TextPainter extends BasePainter {
@Override
void dispose() {
if (myRangeToPrint != null) {
myRangeToPrint.dispose();
myRangeToPrint = null;
}
setSegment(null);
}
}
@@ -52,11 +52,12 @@ print.header.alignment.combobox=Alignment
print.apply.button=A&pply
print.progress=Printing...
print.header.default.line.1=File - $FILE$
print.header.default.line.2=Page $PAGE$
print.header.default.line.2=Page $PAGE$ of $TOTALPAGES$
print.header.placement.header=Header
print.header.placement.footer=Footer
print.header.alignment.left=Left
print.header.alignment.center=Center
print.header.alignment.right=Right
print.file.page.progress=Printing {0}. Page {1}...
print.file.calculating.number.of.pages.progress=Calculating number of pages...
print.file.page.progress=Printing {0}. Page {1} of {2}
file.not.found=File not found: {0}