// This example is from _Java Examples in a Nutshell_. (http://www.oreilly.com)
// Copyright (c) 1997 by David Flanagan
// This example is provided WITHOUT ANY WARRANTY either expressed or implied.
// You may study, use, modify, and distribute it for non-commercial purposes.
// For any commercial use, see http://www.davidflanagan.com/javaexamples
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.text.*;
import java.util.*;
/**
* 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, anyway
pagedpi = toolkit.getScreenResolution();
System.out.println(pagedpi);
// Assume a 8.5" x 11" page size. A4 paper users have to change this.
pagesize = new Dimension((int)(8.5 * pagedpi), 11*pagedpi);
System.out.println(pagesize);
// 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;
System.out.println(fontsize);
System.out.flush();
}
// 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 = toolkit.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 = toolkit.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) {
// 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 a new line.
if (charnum >= chars_per_line) {
newline();
if (page == null) newpage(); // and start a new page, if necessary
}
// 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 the 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 number 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 number 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, .75, .75, .75, .75); }
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);
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 and display it */
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 the panel
p.add(quit);
this.pack(); // Set the size of everything
}
/** 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 the HardcopyWriter, using a 10 point font and 3/4" margins.
HardcopyWriter hw;
try { hw=new HardcopyWriter(this, "Demo Page", 14, .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("+"); for(int i=0;i<cols-2;i++) out.print(" "); out.print("+");
// Display a title
hw.setFontStyle(Font.BOLD + Font.ITALIC);
out.println("\n\n\n\t\tHardcopy Writer Demo Page\n\n\n\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("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
out.println("1234567890!@#$%^&*()[]{}<>,.?:;+-=/\\`'\"_~|");
}
hw.setFontStyle(Font.PLAIN);
out.println("\n\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("01234567890123456789012345678901234567890123456789012345");
out.println("^\t^\t^\t^\t^\t^\t^");
out.println("\n\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 |