/*
* Copyright (c) 2004 David Flanagan. All rights reserved.
* This code is from the book Java Examples in a Nutshell, 3nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose,
* including teaching and use in open-source projects.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book,
* please visit http://www.davidflanagan.com/javaexamples3.
*/
//package je3.print;
import java.awt.Button;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.PrintJob;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.Writer;
import java.text.DateFormat;
import java.util.Date;
import java.util.Properties;
import java.util.TimeZone;
/**
* A character output stream that sends output to a printer.
*/
public class HardcopyWriter extends Writer {
// These are the instance variables for the class
protected PrintJob job; // The PrintJob object in use
protected Graphics page; // Graphics object for current page
protected String jobname; // The name of the print job
protected int fontsize; // Point size of the font
protected String time; // Current time (appears in header)
protected Dimension pagesize; // Size of the page (in dots)
protected int pagedpi; // Page resolution in dots per inch
protected Font font, headerfont; // Body font and header font
protected FontMetrics metrics; // Metrics for the body font
protected FontMetrics headermetrics; // Metrics for the header font
protected int x0, y0; // Upper-left corner inside margin
protected int width, height; // Size (in dots) inside margins
protected int headery; // Baseline of the page header
protected int charwidth; // The width of each character
protected int lineheight; // The height of each line
protected int lineascent; // Offset of font baseline
protected int chars_per_line; // Number of characters per line
protected int lines_per_page; // Number of lines per page
protected int charnum = 0, linenum = 0; // Current column and line position
protected int pagenum = 0; // Current page number
// A field to save state between invocations of the write() method
private boolean last_char_was_return = false;
// A static variable that holds user preferences between print jobs
protected static Properties printprops = new Properties();
/**
* The constructor for this class has a bunch of arguments: The frame argument
* is required for all printing in Java. The jobname appears left justified at
* the top of each printed page. The font size is specified in points, as
* on-screen font sizes are. The margins are specified in inches (or fractions
* of inches).
*/
public HardcopyWriter(Frame frame, String jobname, int fontsize, double leftmargin,
double rightmargin, double topmargin, double bottommargin)
throws HardcopyWriter.PrintCanceledException {
// Get the PrintJob object with which we'll do all the printing.
// The call is synchronized on the static printprops object, which
// means that only one print dialog can be popped up at a time.
// If the user clicks Cancel in the print dialog, throw an exception.
Toolkit toolkit = frame.getToolkit(); // get Toolkit from Frame
synchronized (printprops) {
job = toolkit.getPrintJob(frame, jobname, printprops);
}
if (job == null)
throw new PrintCanceledException("User cancelled print request");
pagesize = job.getPageDimension(); // query the page size
pagedpi = job.getPageResolution(); // query the page resolution
// Bug Workaround:
// On windows, getPageDimension() and getPageResolution don't work, so
// we've got to fake them.
if (System.getProperty("os.name").regionMatches(true, 0, "windows", 0, 7)) {
// Use screen dpi, which is what the PrintJob tries to emulate
pagedpi = toolkit.getScreenResolution();
// Assume a 8.5" x 11" page size. A4 paper users must change this.
pagesize = new Dimension((int) (8.5 * pagedpi), 11 * pagedpi);
// We also have to adjust the fontsize. It is specified in points,
// (1 point = 1/72 of an inch) but Windows measures it in pixels.
fontsize = fontsize * pagedpi / 72;
}
// Compute coordinates of the upper-left corner of the page.
// I.e. the coordinates of (leftmargin, topmargin). Also compute
// the width and height inside of the margins.
x0 = (int) (leftmargin * pagedpi);
y0 = (int) (topmargin * pagedpi);
width = pagesize.width - (int) ((leftmargin + rightmargin) * pagedpi);
height = pagesize.height - (int) ((topmargin + bottommargin) * pagedpi);
// Get body font and font size
font = new Font("Monospaced", Font.PLAIN, fontsize);
metrics = frame.getFontMetrics(font);
lineheight = metrics.getHeight();
lineascent = metrics.getAscent();
charwidth = metrics.charWidth('0'); // Assumes a monospaced font!
// Now compute columns and lines will fit inside the margins
chars_per_line = width / charwidth;
lines_per_page = height / lineheight;
// Get header font information
// And compute baseline of page header: 1/8" above the top margin
headerfont = new Font("SansSerif", Font.ITALIC, fontsize);
headermetrics = frame.getFontMetrics(headerfont);
headery = y0 - (int) (0.125 * pagedpi) - headermetrics.getHeight() + headermetrics.getAscent();
// Compute the date/time string to display in the page header
DateFormat df = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.SHORT);
df.setTimeZone(TimeZone.getDefault());
time = df.format(new Date());
this.jobname = jobname; // save name
this.fontsize = fontsize; // save font size
}
/**
* This is the write() method of the stream. All Writer subclasses implement
* this. All other versions of write() are variants of this one
*/
public void write(char[] buffer, int index, int len) {
synchronized (this.lock) { // For thread safety
// Loop through all the characters passed to us
for (int i = index; i < index + len; i++) {
// If we haven't begun a page (or a new page), do that now.
if (page == null)
newpage();
// If the character is a line terminator, then begin new line,
// unless it is a \n immediately after a \r.
if (buffer[i] == '\n') {
if (!last_char_was_return)
newline();
continue;
}
if (buffer[i] == '\r') {
newline();
last_char_was_return = true;
continue;
} else
last_char_was_return = false;
// If it some other non-printing character, ignore it.
if (Character.isWhitespace(buffer[i]) && !Character.isSpaceChar(buffer[i])
&& (buffer[i] != '\t'))
continue;
// If no more characters will fit on the line, start new line.
if (charnum >= chars_per_line) {
newline();
// Also start a new page, if necessary
if (page == null)
newpage();
}
// Now print the character:
// If it is a space, skip one space, without output.
// If it is a tab, skip the necessary number of spaces.
// Otherwise, print the character.
// It is inefficient to draw only one character at a time, but
// because our FontMetrics don't match up exactly to what the
// printer uses we need to position each character individually
if (Character.isSpaceChar(buffer[i]))
charnum++;
else if (buffer[i] == '\t')
charnum += 8 - (charnum % 8);
else {
page.drawChars(buffer, i, 1, x0 + charnum * charwidth, y0 + (linenum * lineheight)
+ lineascent);
charnum++;
}
}
}
}
/**
* This is the flush() method that all Writer subclasses must implement. There
* is no way to flush a PrintJob without prematurely printing the page, so we
* don't do anything.
*/
public void flush() { /* do nothing */
}
/**
* This is the close() method that all Writer subclasses must implement. Print
* the pending page (if any) and terminate the PrintJob.
*/
public void close() {
synchronized (this.lock) {
if (page != null)
page.dispose(); // Send page to the printer
job.end(); // Terminate the job
}
}
/**
* Set the font style. The argument should be one of the font style constants
* defined by the java.awt.Font class. All subsequent output will be in that
* style. This method relies on all styles of the Monospaced font having the
* same metrics.
*/
public void setFontStyle(int style) {
synchronized (this.lock) {
// Try to set a new font, but restore current one if it fails
Font current = font;
try {
font = new Font("Monospaced", style, fontsize);
} catch (Exception e) {
font = current;
}
// If a page is pending, set the new font. Otherwise newpage() will
if (page != null)
page.setFont(font);
}
}
/** End the current page. Subsequent output will be on a new page. */
public void pageBreak() {
synchronized (this.lock) {
newpage();
}
}
/** Return the number of columns of characters that fit on the page */
public int getCharactersPerLine() {
return this.chars_per_line;
}
/** Return the number of lines that fit on a page */
public int getLinesPerPage() {
return this.lines_per_page;
}
/** This internal method begins a new line */
protected void newline() {
charnum = 0; // Reset character number to 0
linenum++; // Increment line number
if (linenum >= lines_per_page) { // If we've reached the end of page
page.dispose(); // send page to printer
page = null; // but don't start a new page yet.
}
}
/** This internal method begins a new page and prints the header. */
protected void newpage() {
page = job.getGraphics(); // Begin the new page
linenum = 0;
charnum = 0; // Reset line and char number
pagenum++; // Increment page number
page.setFont(headerfont); // Set the header font.
page.drawString(jobname, x0, headery); // Print job name left justified
String s = "- " + pagenum + " -"; // Print the page # centered.
int w = headermetrics.stringWidth(s);
page.drawString(s, x0 + (this.width - w) / 2, headery);
w = headermetrics.stringWidth(time); // Print date right justified
page.drawString(time, x0 + width - w, headery);
// Draw a line beneath the header
int y = headery + headermetrics.getDescent() + 1;
page.drawLine(x0, y, x0 + width, y);
// Set the basic monospaced font for the rest of the page.
page.setFont(font);
}
/**
* This is the exception class that the HardcopyWriter constructor throws when
* the user clicks "Cancel" in the print dialog box.
*/
public static class PrintCanceledException extends Exception {
public PrintCanceledException(String msg) {
super(msg);
}
}
/**
* A program that prints the specified file using HardcopyWriter
*/
public static class PrintFile {
public static void main(String[] args) {
try {
if (args.length != 1)
throw new IllegalArgumentException("Wrong # of arguments");
FileReader in = new FileReader(args[0]);
HardcopyWriter out = null;
Frame f = new Frame("PrintFile: " + args[0]);
f.setSize(200, 50);
f.show();
try {
out = new HardcopyWriter(f, args[0], 10, .5, .5, .5, .5);
} catch (HardcopyWriter.PrintCanceledException e) {
System.exit(0);
}
f.setVisible(false);
char[] buffer = new char[4096];
int numchars;
while ((numchars = in.read(buffer)) != -1)
out.write(buffer, 0, numchars);
in.close();
out.close();
} catch (Exception e) {
System.err.println(e);
System.err.println("Usage: " + "java HardcopyWriter$PrintFile <filename>");
System.exit(1);
}
System.exit(0);
}
}
/**
* A program that prints a demo page using HardcopyWriter
*/
public static class Demo extends Frame implements ActionListener {
/** The main method of the program. Create a test window */
public static void main(String[] args) {
Frame f = new Demo();
f.show();
}
// Buttons used in this program
protected Button print, quit;
/** Constructor for the test program's window. */
public Demo() {
super("HardcopyWriter Test"); // Call frame constructor
Panel p = new Panel(); // Add a panel to the frame
this.add(p, "Center"); // Center it
p.setFont(new Font("SansSerif", // Set a default font
Font.BOLD, 18));
print = new Button("Print Test Page"); // Create a Print button
quit = new Button("Quit"); // Create a Quit button
print.addActionListener(this); // Specify that we'll handle
quit.addActionListener(this); // button presses
p.add(print); // Add the buttons to panel
p.add(quit);
this.pack(); // Set the frame size
}
/** Handle the button presses */
public void actionPerformed(ActionEvent e) {
Object o = e.getSource();
if (o == quit)
System.exit(0);
else if (o == print)
printDemoPage();
}
/** Print the demo page */
public void printDemoPage() {
// Create a HardcopyWriter, using a 10 point font and 3/4" margins.
HardcopyWriter hw;
try {
hw = new HardcopyWriter(this, "Demo Page", 10, .75, .75, .75, .75);
} catch (HardcopyWriter.PrintCanceledException e) {
return;
}
// Send output to it through a PrintWriter stream
PrintWriter out = new PrintWriter(hw);
// Figure out the size of the page
int rows = hw.getLinesPerPage(), cols = hw.getCharactersPerLine();
// Mark upper left and upper-right corners
out.print("+"); // upper-left corner
for (int i = 0; i < cols - 2; i++)
out.print(" "); // space over
out.print("+"); // upper-right corner
// Display a title
hw.setFontStyle(Font.BOLD + Font.ITALIC);
out.println("\n\t\tHardcopy Writer Demo Page\n\n");
// Demonstrate font styles
hw.setFontStyle(Font.BOLD);
out.println("Font Styles:");
int[] styles = { Font.PLAIN, Font.BOLD, Font.ITALIC, Font.ITALIC + Font.BOLD };
for (int i = 0; i < styles.length; i++) {
hw.setFontStyle(styles[i]);
out.println("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz");
out.println("1234567890!@#$%^&*()[]{}<>,.?:;+-=/\\`'\"_~|");
}
hw.setFontStyle(Font.PLAIN);
out.println("\n");
// Demonstrate tab stops
hw.setFontStyle(Font.BOLD);
out.println("Tab Stops:");
hw.setFontStyle(Font.PLAIN);
out.println(" 1 2 3 4 5");
out.println("012345678901234567890123456789012345678901234567890");
out.println("^\t^\t^\t^\t^\t^\t^");
out.println("\n");
// Output some information about page dimensions and resolution
hw.setFontStyle(Font.BOLD);
out.println("Dimensions:");
hw.setFontStyle(Font.PLAIN);
out.println("\tResolution: " + hw.pagedpi + " dots per inch");
out.println("\tPage width (pixels): " + hw.pagesize.width);
out.println("\tPage height (pixels): " + hw.pagesize.height);
out.println("\tWidth inside margins (pixels): " + hw.width);
out.println("\tHeight inside margins (pixels): " + hw.height);
out.println("\tCharacters per line: " + cols);
out.println("\tLines per page: " + rows);
// Skip down to the bottom of the page
for (int i = 0; i < rows - 30; i++)
out.println();
// And mark the lower left and lower right
out.print("+"); // lower-left
for (int i = 0; i < cols - 2; i++)
out.print(" "); // space-over
out.print("+"); // lower-right
// Close the output stream, forcing the page to be printed
out.close();
}
}
}
|