Listing 4

118:    /**
119:     * Class: Document <p>
120:     *
121:     * This class is the painter for the document content.<p>
122:     *
123:     *
124:     * @author Jean-Pierre Dube <jpdube@videotron.ca>
125:     * @version 1.0
126:     * @since 1.0
127:     * @see Printable
128:     */
129:    private class Document implements Printable {
130: 
131: 
132:       /**
133:        * Method: print <p>
134:        *
135:        * @param g a value of type Graphics
136:        * @param pageFormat a value of type PageFormat
137:        * @param page a value of type int
138:        * @return a value of type int
139:        */
140:       public int print (Graphics g, PageFormat pageFormat, int page) {
141: 
142: 
143:          //--- Create the Graphics2D object
144:          Graphics2D g2d = (Graphics2D) g;
145: 
146:          //--- Translate the origin to 0,0 for the top left corner
147:          g2d.translate (pageFormat.getImageableX (), pageFormat.getImageableY ());
148: 
149:          //--- Set the drawing color to black
150:          g2d.setPaint (Color.black);
151: 
152:          //--- Draw a border around the page using a 12 point border
153:          g2d.setStroke (new BasicStroke (4));
154:          Rectangle2D.Double border = new Rectangle2D.Double (0,
155:                                                              0,
156:                                                              pageFormat.getImageableWidth (),
157:                                                              pageFormat.getImageableHeight ());
158: 
159:          g2d.draw (border);
160: 
161: 
162:          //--- Create a string and assign the text
163:          String text = new String ();
164:          text += "Manipulating raw fonts would be too complicated to render paragraphs of ";
165:          text += "text. Trying to write an algorithm to fully justify text using ";         
166:          text += "proportional fonts is not trivial. Adding support for international ";    
167:          text += "characters adds to the complexity. That's why we will use the ";         
168:          text += "TextLayout and the LineBreakMeasurer class to "; 
169:          text += "render text. The TextLayout class offers a lot of ";          
170:          text += "functionality to render high quality text. This class is capable of ";    
171:          text += "rendering bidirectional text such as Japanese text where the alignment "; 
172:          text += "is from right to left instead of the North American style which is left ";
173:          text += "to right. The TextLayout class offers some additional ";      
174:          text += "functionalities that we will not use in the course of this ";             
175:          text += "series. Features such as text input, caret positioning and hit ";        
176:          text += "testing will not be of much use when printing documents, but it's good "; 
177:          text += "to know that this functionality exists. ";
178:          
179:          text += "The TextLayout class will be used to layout ";               
180:          text += "paragraphs. The TextLayout class does not work alone. To ";  
181:          text += "layout text within a specified width it needs the help of the ";         
182:          text += "LineBreakMeasurer class. This class will wrap a string of "; 
183:          text += "text to fit a predefined width. Since it's a multi-lingual class, it ";   
184:          text += "knows exactly where to break a line of text according to the rules ";     
185:          text += "of the language.  Then again the LineBreakMeasurer does ";   
186:          text += "not work alone. It needs information from the ";
187:          text += "FontRenderContext class. This class' main function is to ";  
188:          text += "return accurate font metrics. To measure text effectively, this class ";  
189:          text += "needs to know the rendering hints for the targeted device and the font "; 
190:          text += "type being used. ";  
191: 
192: 
193:          //--- Create a point object to set the top left corner of the TextLayout object
194:          Point2D.Double pen = new Point2D.Double (0.25 * POINTS_PER_INCH, 0.25 * POINTS_PER_INCH);
195: 
196:          //--- Set the width of the TextLayout box
197:          double width = 7.5 * POINTS_PER_INCH;
198: 
199: 
200:          //--- Create an attributed string from the text string. We are creating an
201:          //--- attributed string because the LineBreakMeasurer needs an Iterator as
202:          //--- parameter.
203:          AttributedString paragraphText = new AttributedString (text);
204: 
205:          //--- Set the font for this text
206:          paragraphText.addAttribute (TextAttribute.FONT, new Font ("serif", Font.PLAIN, 12));
207: 
208:          //--- Create a LineBreakMeasurer to wrap the text for the TextLayout object
209:          //--- Note the second parameter, the FontRendereContext. I have set the second
210:          //--- parameter antiAlised to true and the third parameter useFractionalMetrics
211:          //--- to true to get the best possible output
212:          LineBreakMeasurer lineBreaker = new LineBreakMeasurer (paragraphText.getIterator(),
213:                                                                 new FontRenderContext (null, true, true));
214: 
215:          //--- Create the TextLayout object
216:          TextLayout layout;
217: 
218:          //--- LineBreakMeasurer will wrap each line to correct length and
219:          //--- return it as a TextLayout object
220:          while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
221: 
222:             //--- Align the Y pen to the ascend of the font, remember that
223:             //--- the ascend is origin (0, 0) of a font. Refer to Figure 1
224:             pen.y += layout.getAscent ();
225: 
226:             //--- Draw the line of text
227:             layout.draw (g2d, (float) pen.x, (float) pen.y);
228: 
229:             //--- Move the pen to the next position adding the descent and
230:             //--- the leading of the font
231:             pen.y += layout.getDescent () + layout.getLeading ();
232:          }
233: 
234:          //--- Validate the page
235:          return (PAGE_EXISTS);
236:       }
237:    }
238: 
239: } // Example4