1|package com.infocom.print;
  2|
  3|
  4|/**
  5| * Class: PFParagraph <p>
  6| *
  7| * Render a paragraph of text.<p>
  8| *
  9| * Using this class you will be able to render a paragraph of text
 10| * with the following attributes:
 11| *
 12| * <ul>
 13| * <li>Set the font of the text. If an <code>AttributedString</code> is used
 14| * you must then specify the font in the <code>AttributedStrin</code> itself</li>
 15| *
 16| * <li>Set the text color, again if an <code>AttributedString</code> is used,
 17| * then you must specify the text color in the <code>AttributedString</code></li>
 18| *
 19| * <li>Justify the text using the following attribute: Left, Right, Center and
 20| * full justification</li>
 21| *
 22| * <li>Provide paragraph metrics, using the getTextHeight () will return the height
 23| * in <code>PFUnit</code> of the rendered text</li>
 24| *
 25| * <li>Provide the position of the next paragraph with the
 26| * <code>getNextParagraphPosition</code> method
 27| *
 28| * <li>Automatic height adjustement in relation with the paragraph
 29| * height</li>
 30| * </ul>
 31| *
 32| * @author Jean-Pierre Dube <jpdube@videotron.ca>
 33| * @version 1.0
 34| * @since 1.0
 35| * @see PFPrintObject
 36| */
 37|
 38|import java.awt.Graphics2D;
 39|import java.text.AttributedString;
 40|import java.util.Vector;
 41|import java.awt.Font;
 42|import java.awt.Color;
 43|import java.awt.font.TextAttribute;
 44|import java.awt.geom.Point2D;
 45|import java.awt.font.LineBreakMeasurer;
 46|import java.awt.font.TextLayout;
 47|import java.awt.font.FontRenderContext;
 48|
 49|
 50|public class PFParagraph extends PFPrintObject {
 51|
 52|   //--- Public constants declarations
 53|   public static final int LEFT_JUSTIFIED = 0;
 54|   public static final int RIGHT_JUSTIFIED = 1;
 55|   public static final int CENTER_JUSTIFIED = 2;
 56|   public static final int FULL_JUSTIFIED = 3;
 57|
 58|   //--- Private instances declarations
 59|   private AttributedString text;
 60|   private Font font = new Font ("serif", Font.PLAIN, 12);
 61|   private int horizontalAlignment = LEFT_JUSTIFIED;
 62|   private Color textColor = Color.black;
 63|   private boolean autoAdjustHeight = false;
 64|
 65|
 66|   /**
 67|    * Constructor: PFParagraph <p>
 68|    *
 69|    */
 70|   public PFParagraph () {
 71|
 72|   }
 73|
 74|
 75|   /**
 76|    * Constructor: PFParagraph <p>
 77|    *
 78|    * Create a paragraph object using an <code>AttributedString</code>
 79|    *
 80|    * @param parText a value of type AttributedText
 81|    */
 82|   public PFParagraph (AttributedString parText) {
 83|
 84|      text = parText;
 85|   }
 86|
 87|
 88|   /**
 89|    * Method: setText <p>
 90|    *
 91|    * Set the paragraph text by providing an
 92|    * <code>AttributedString</code> class
 93|    *
 94|    * Upon setting the paragraph text, this method
 95|    * will check if the autoAdjustHeight flag is set.
 96|    * If <code>true</code> then the height of the
 97|    * object is adjusted appropriatly. Else the text
 98|    * will be clipped in the rendering process.
 99|    *
100|    * @param parText a value of type AttributedString
101|    */
102|   public void setText (AttributedString parText) {
103|
104|      //--- Set text content
105|      text = parText;
106|
107|      //--- Auto adjust height
108|      if (autoAdjustHeight)
109|         setHeight (getTextHeight ());
110|
111|   }
112|
113|
114|   /**
115|    * Method: setText <p>
116|    *
117|    * @param parText a value of type String
118|    */
119|   public void setText (String parText) {
120|
121|      text = new AttributedString (parText);
122|      text.addAttribute (TextAttribute.FONT, new Font ("serif", Font.PLAIN, 12));
123|      setText (text);
124|   }
125|
126|
127|   /**
128|    * Method: autoAdjustHeight <p>
129|    *
130|    * @param parAutoAdjust a value of type boolean
131|    */
132|   public void setAutoAdjustHeight (boolean parAutoAdjust) {
133|
134|      autoAdjustHeight = parAutoAdjust;
135|   }
136|
137|
138|   /**
139|    * Method: isAutoAdjustHeight <p>
140|    *
141|    * @return a value of type boolean
142|    */
143|   public boolean isAutoAdjustHeight () {
144|
145|      return (autoAdjustHeight);
146|
147|   }
148|
149|
150|   /**
151|    * Method: setHorizontalAligment <p>
152|    *
153|    * @param parAlignment a value of type int
154|    */
155|   public void setHorizontalAlignment (int parAlignment) {
156|
157|      horizontalAlignment = parAlignment;
158|
159|   }
160|
161|
162|   /**
163|    * Method: getHorizontalAlignment <p>
164|    *
165|    * @return a value of type int
166|    */
167|   public int getHorizontalAlignment () {
168|
169|      return (horizontalAlignment);
170|
171|   }
172|
173|
174|   /**
175|    * Method: print <p>
176|    *
177|    * @param parG a value of type Graphics2D
178|    */
179|   public void print (Graphics2D parG) {
180|
181|      //--- Compute position and size
182|      computePositionAndSize ();
183|
184|      //--- Draw paragraph
185|      parG.setColor (textColor);
186|      parG.setFont (font);
187|
188|      switch (horizontalAlignment) {
189|         case LEFT_JUSTIFIED:
190|            renderLeftJustified (parG);
191|            break;
192|
193|         case RIGHT_JUSTIFIED:
194|            renderRightJustified (parG);
195|            break;
196|
197|         case CENTER_JUSTIFIED:
198|            renderCenterJustified (parG);
199|            break;
200|
201|         case FULL_JUSTIFIED:
202|            renderFullyJustified (parG);
203|            break;
204|      }
205|
206|      //--- Print childs
207|      printChilds (parG);
208|   }
209|
210|
211|   /**
212|    * Method: getTextHeight <p>
213|    *
214|    * @return a value of type PFUnit
215|    */
216|   public PFUnit getTextHeight () {
217|
218|
219|      PFInchUnit textHeight = new PFInchUnit (0.0);
220|
221|
222|      //--- Compute position and size
223|      computePositionAndSize ();
224|
225|      //--- Create a point object to set the top left corner of the TextLayout object
226|      Point2D.Double pen = new Point2D.Double (0.0, 0.0);
227|
228|      //--- Set the width of the TextLayout box
229|      double width = getDrawingSize ().getWidth ().getPoints ();
230|
231|      //--- LineBreakMeasurer
232|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
233|                                                             new FontRenderContext (null, true, true));
234|
235|      //--- Create the TextLayout object
236|      TextLayout layout;
237|
238|      //--- LineBreakMeasurer will wrap each line to correct length and
239|      //--- return it as a TextLayout object
240|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
241|
242|         //--- Align the Y pen to the ascend of the font, remember that
243|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
244|         pen.y += layout.getAscent () + layout.getDescent () + layout.getLeading ();
245|      }
246|
247|      textHeight.setPoints (pen.y);
248|
249|      return (textHeight);
250|   }
251|
252|
253|   /**
254|    * Method: getNextParagraphPosition <p>
255|    *
256|    * @return a value of type PFPoint
257|    */
258|   public PFPoint getNextParagraphPosition () {
259|
260|      double lastAscent = 0.0;
261|
262|
263|      //--- Compute position and size
264|      computePositionAndSize ();
265|
266|      //--- Create a point object to set the top left corner of the TextLayout object
267|      Point2D.Double pen = new Point2D.Double (0.0, 0.0); //getDrawingOrigin ().getPoint2D ();
268|
269|      //--- Set the width of the TextLayout box
270|      double width = getDrawingSize ().getWidth ().getPoints ();
271|
272|      //--- LineBreakMeasurer
273|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
274|                                                             new FontRenderContext (null, true, true));
275|
276|      //--- Create the TextLayout object
277|      TextLayout layout;
278|
279|      //--- LineBreakMeasurer will wrap each line to correct length and
280|      //--- return it as a TextLayout object
281|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
282|
283|         //--- Align the Y pen to the ascend of the font, remember that
284|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
285|         pen.y += layout.getAscent () + layout.getDescent () + layout.getLeading ();
286|         lastAscent = layout.getAscent ();
287|      }
288|
289|      PFInchUnit y = new PFInchUnit ();
290|      y.setPoints (pen.y);
291|      return (new PFPoint (getPosition ().getX (), y));
292|   }
293|
294|
295|   /**
296|    * Method: renderCenterJustified <p>
297|    *
298|    * @param parG a value of type Graphics2D
299|    */
300|   private void renderCenterJustified (Graphics2D parG) {
301|
302|      //--- Create a point object to set the top left corner of the TextLayout object
303|      Point2D.Double pen = getDrawingOrigin ().getPoint2D ();
304|
305|      //--- Set the width of the TextLayout box
306|      double width = getDrawingSize ().getWidth ().getPoints ();
307|
308|      //--- LineBreakMeasurer
309|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
310|                                                             new FontRenderContext (null, true, true));
311|
312|      //--- Create the TextLayout object
313|      TextLayout layout;
314|      float layoutX;
315|
316|      //--- LineBreakMeasurer will wrap each line to correct length and
317|      //--- return it as a TextLayout object
318|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
319|
320|         //--- Align the Y pen to the ascend of the font, remember that
321|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
322|         pen.y += layout.getAscent ();
323|
324|         //--- Align the X pen to right justified the line
325|         layoutX = ((float) (pen.x + (width / 2))) - (layout.getAdvance () / 2);
326|
327|         //--- Draw the line of text
328|         layout.draw (parG, layoutX, (float) pen.y);
329|
330|         //--- Move the pen to the next position adding the descent and
331|         //--- the leading of the font
332|         pen.y += layout.getDescent () + layout.getLeading ();
333|      }
334|
335|   }
336|
337|
338|
339|   /**
340|    * Method: renderRightJustified <p>
341|    *
342|    * @param parG a value of type Graphics2D
343|    */
344|   private void renderRightJustified (Graphics2D parG) {
345|
346|      //--- Create a point object to set the top left corner of the TextLayout object
347|      Point2D.Double pen = getDrawingOrigin ().getPoint2D ();
348|
349|      //--- Set the width of the TextLayout box
350|      double width = getDrawingSize ().getWidth ().getPoints ();
351|
352|      //--- LineBreakMeasurer
353|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
354|                                                             new FontRenderContext (null, true, true));
355|
356|      //--- Create the TextLayout object
357|      TextLayout layout;
358|      float layoutX;
359|
360|      //--- LineBreakMeasurer will wrap each line to correct length and
361|      //--- return it as a TextLayout object
362|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
363|
364|         //--- Align the Y pen to the ascend of the font, remember that
365|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
366|         pen.y += layout.getAscent ();
367|
368|         //--- Align the X pen to right justified the line
369|         layoutX = ((float) (pen.x + width)) - layout.getAdvance ();
370|
371|         //--- Draw the line of text
372|         layout.draw (parG, layoutX, (float) pen.y);
373|
374|         //--- Move the pen to the next position adding the descent and
375|         //--- the leading of the font
376|         pen.y += layout.getDescent () + layout.getLeading ();
377|      }
378|
379|   }
380|
381|
382|   /**
383|    * Method: renderLeftJustified <p>
384|    *
385|    * @param parG a value of type Graphics2D
386|    */
387|   private void renderLeftJustified (Graphics2D parG) {
388|
389|      //--- Create a point object to set the top left corner of the TextLayout object
390|      Point2D.Double pen = getDrawingOrigin ().getPoint2D ();
391|
392|      //--- Set the width of the TextLayout box
393|      double width = getDrawingSize ().getWidth ().getPoints ();
394|
395|      //--- LineBreakMeasurer
396|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
397|                                                             new FontRenderContext (null, true, true));
398|
399|      //--- Create the TextLayout object
400|      TextLayout layout;
401|
402|      //--- LineBreakMeasurer will wrap each line to correct length and
403|      //--- return it as a TextLayout object
404|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
405|
406|         //--- Align the Y pen to the ascend of the font, remember that
407|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
408|         pen.y += layout.getAscent ();
409|
410|         //--- Draw the line of text
411|         layout.draw (parG, (float) pen.x, (float) pen.y);
412|
413|         //--- Move the pen to the next position adding the descent and
414|         //--- the leading of the font
415|         pen.y += layout.getDescent () + layout.getLeading ();
416|      }
417|
418|   }
419|
420|
421|   /**
422|    * Method: renderFullJustification <p>
423|    *
424|    * @param parG a value of type Graphics2D
425|    */
426|   private void renderFullyJustified (Graphics2D parG) {
427|
428|      //--- Create a point object to set the top left corner of the TextLayout object
429|      Point2D.Double pen = getDrawingOrigin ().getPoint2D ();
430|
431|      //--- Set the width of the TextLayout box
432|      double width = getDrawingSize ().getWidth ().getPoints ();
433|
434|      //--- LineBreakMeasurer
435|      LineBreakMeasurer lineBreaker = new LineBreakMeasurer (text.getIterator(),
436|                                                             new FontRenderContext (null, true, true));
437|
438|      //--- Create the TextLayouts object
439|      TextLayout layout;
440|      TextLayout justifyLayout;
441|
442|      //--- Create a Vector to temporaly store each line of text
443|      Vector lines = new Vector ();
444|
445|      //--- Get the output of the LineBreakMeasurer and store it in a Vector
446|      while ((layout = lineBreaker.nextLayout ((float) width)) != null) {
447|         lines.add (layout);
448|
449|      }
450|
451|      //--- Scan each line of the paragraph and justify it except for the last line
452|      for (int i = 0; i < lines.size (); i++) {
453|
454|         //--- Get the line from the vector
455|         layout = (TextLayout) lines.get (i);
456|
457|         //--- Check for the last line. When found print it
458|         //--- without justification
459|         if (i != lines.size () - 1)
460|            justifyLayout = layout.getJustifiedLayout ((float) width);
461|         else
462|            justifyLayout = layout;
463|
464|         //--- Align the Y pen to the ascend of the font, remember that
465|         //--- the ascend is origin (0, 0) of a font. Refer to figure 1
466|         pen.y += justifyLayout.getAscent ();
467|
468|         //--- Draw the line of text
469|         justifyLayout.draw (parG, (float) pen.x, (float) pen.y);
470|
471|         //--- Move the pen to the next position adding the descent and
472|         //--- the leading of the font
473|         pen.y += justifyLayout.getDescent () + justifyLayout.getLeading ();
474|
475|      }
476|   }
477|
478|
479|   /**
480|    * Method: setFont <p>
481|    *
482|    * @param parFont a value of type Font
483|    */
484|   public void setFont (Font parFont) {
485|
486|      if (parFont != null)
487|         font = parFont;
488|
489|   }
490|
491|
492|   /**
493|    * Method: getFont <p>
494|    *
495|    * @return a value of type Font
496|    */
497|   public Font getFont () {
498|
499|      return (font);
500|
501|   }
502|
503|
504|   /**
505|    * Method: setTextColor <p>
506|    *
507|    * @param parTextColor a value of type Color
508|    */
509|   public void setTextColor (Color parTextColor) {
510|
511|      //--- Require
512|      if (parTextColor != null) {
513|         textColor = parTextColor;
514|      }
515|
516|   }
517|
518|
519|   /**
520|    * Method: getTextColor <p>
521|    *
522|    * @return a value of type Color
523|    */
524|   public Color getTextColor () {
525|
526|      return (textColor);
527|
528|   }
529|}// PFParagraph