Mega Code Archive

 
Categories / Java / File Input Output
 

A character output stream that sends output to a printer

/*  * 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();     }   } }