]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.document.linking.ui/src/org/simantics/document/linking/report/pdf/PDFTable.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.document.linking.ui / src / org / simantics / document / linking / report / pdf / PDFTable.java
diff --git a/bundles/org.simantics.document.linking.ui/src/org/simantics/document/linking/report/pdf/PDFTable.java b/bundles/org.simantics.document.linking.ui/src/org/simantics/document/linking/report/pdf/PDFTable.java
new file mode 100644 (file)
index 0000000..8f9dafa
--- /dev/null
@@ -0,0 +1,667 @@
+package org.simantics.document.linking.report.pdf;\r
+\r
+import java.awt.Color;\r
+import java.awt.Font;\r
+import java.awt.Graphics2D;\r
+import java.awt.Shape;\r
+import java.awt.font.LineBreakMeasurer;\r
+import java.awt.font.TextAttribute;\r
+import java.awt.font.TextLayout;\r
+import java.net.URL;\r
+import java.text.AttributedCharacterIterator;\r
+import java.text.AttributedString;\r
+import java.util.ArrayList;\r
+import java.util.Collections;\r
+import java.util.Hashtable;\r
+import java.util.List;\r
+\r
+import org.simantics.document.linking.report.Document.TextSize;\r
+import org.simantics.document.linking.report.Table;\r
+import org.simantics.document.linking.report.TableColumn;\r
+import org.simantics.document.linking.report.TableColumn.Alignment;\r
+import org.simantics.document.linking.report.TableRow;\r
+import org.simantics.document.linking.report.TextItem;\r
+import org.simantics.document.linking.report.URLItem;\r
+\r
+import com.lowagie.text.pdf.PdfAction;\r
+\r
+\r
+public class PDFTable implements Table, PDFElement {\r
+       PDFDocument writer;\r
+       PDFPageStream stream;\r
+       PDFPage startPage;\r
+       \r
+       int currentLine = 0;\r
+       \r
+       List<TableColumn> columns = new ArrayList<TableColumn>();\r
+       List<String> columnNames = new ArrayList<String>();\r
+       List<Integer> columnSizes = new ArrayList<Integer>();\r
+       List<Integer> columnPositions = new ArrayList<Integer>();\r
+       \r
+       TextItem title = null;\r
+       \r
+       boolean headerVisible = true;\r
+       private boolean linesVisible = true;\r
+       private boolean linesPrevVisible = true;\r
+       boolean clipText = false;\r
+       \r
+       int textOffsetX = 2;\r
+       int textOffsetY = 2;\r
+       \r
+       public PDFTable(PDFDocument writer, PDFPageStream stream) {\r
+               this.writer = writer;\r
+               this.stream = stream;\r
+               this.startPage = stream.getCurrentPage();\r
+               \r
+       }\r
+       \r
+       public PDFTable(PDFTable table) {\r
+               this.writer = table.writer;\r
+               this.stream = table.stream;\r
+               this.startPage = stream.getCurrentPage();\r
+               this.columns.addAll(table.columns);\r
+               this.columnNames.addAll(table.columnNames);\r
+               \r
+               updateColumnPositions();\r
+       }\r
+       \r
+       \r
+       @Override\r
+       public PDFPage getPage() {\r
+               return startPage;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see org.simantics.document.linking.report.Table#addColumn(java.lang.String, double)\r
+        */\r
+       @Override\r
+       public TableColumn addColumn(String name, double width) {\r
+               TableColumn tc = new TableColumn(name, width);\r
+               columns.add(tc);\r
+               columnNames.add(name);\r
+               \r
+               updateColumnPositions();\r
+               return tc;\r
+       }\r
+       \r
+       private void updateColumnPositions() {\r
+               int pos = 0;\r
+               columnSizes.clear();\r
+               columnPositions.clear();\r
+               for (TableColumn c : columns) {\r
+                       int size = (int)(c.getWidth()*stream.getContentWidth());\r
+                       columnSizes.add(size);\r
+                       columnPositions.add(pos);\r
+                       pos+=size;\r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public List<TableColumn> getColumns() {\r
+               return columns;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isLinesVisible() {\r
+               return linesVisible;\r
+       }\r
+       \r
+       @Override\r
+       public void setLinesVisible(boolean b) {\r
+               if (this.linesVisible == b)\r
+                       return;\r
+               this.linesPrevVisible = linesVisible;\r
+               this.linesVisible = b;\r
+       }\r
+       \r
+       @Override\r
+       public boolean isHeaderVisible() {\r
+               return headerVisible;\r
+       }\r
+       \r
+       @Override\r
+       public void setHeaderVisible(boolean b) {\r
+               this.headerVisible = b;\r
+       }\r
+       \r
+       private boolean isFirstLine() {\r
+               return currentLine == 0 || stream.getCurrentPage().currentLine == 1;\r
+       }\r
+       \r
+       @Override\r
+       public void setTitle(String title) {\r
+               try {\r
+                       this.title = writer.newItem(TextItem.class);\r
+                       this.title.setText(title);\r
+               } catch (Exception e) {\r
+                       \r
+               }\r
+       }\r
+       \r
+       @Override\r
+       public void setTitle(TextItem title){\r
+               this.title = title;\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see org.simantics.document.linking.report.Table#writeRow(java.lang.String[])\r
+        */\r
+       @Override\r
+       public TableRow writeRow(String... line) throws Exception{\r
+               List<String> list = new ArrayList<String>(line.length);\r
+               for (String s : line)\r
+                       list.add(s);\r
+               return writeRow(list);\r
+       }\r
+       \r
+       /* (non-Javadoc)\r
+        * @see org.simantics.document.linking.report.Table#writeRow(java.util.List)\r
+        */\r
+       @Override\r
+       public TableRow writeRow(List<String> line) throws Exception{\r
+               if (isFirstLine())\r
+                       writeHeader();\r
+               return _writeRow(line);\r
+       }\r
+       \r
+       @Override\r
+       public TableRow writeRowItem(TextItem... line) throws Exception {\r
+               List<TextItem> list = new ArrayList<TextItem>(line.length);\r
+               for (TextItem s : line)\r
+                       list.add(s);\r
+               return writeRowItem(list);\r
+       }\r
+       \r
+       @Override\r
+       public TableRow writeRowItem(List<TextItem> line) throws Exception {\r
+               if (isFirstLine())\r
+                       writeHeader();\r
+               return _writeRow2(line);\r
+       }\r
+       \r
+       private TableRow _writeRow(List<String> line) throws Exception {\r
+               int h = getTextHeight();\r
+               int ht = getTopHeight();\r
+               int hb = getBottomHeight();\r
+               PDFPage page = getCurrentPage();\r
+               Graphics2D g2d = page.g2d;\r
+               Shape clip = g2d.getClip();\r
+               \r
+               if (clipText) {\r
+                       for (int i = 0; i < line.size(); i++) {\r
+                               if (line.get(i) == null)\r
+                                       continue;\r
+                               g2d.setClip(columnPositions.get(i),ht-1,columnSizes.get(i),hb-ht+2);\r
+                               g2d.drawString(line.get(i), columnPositions.get(i)+textOffsetX, h);\r
+                       }\r
+                       g2d.setClip(clip);\r
+                       if (linesVisible) {\r
+                               for (int i = 0; i < line.size(); i++) {\r
+                                       g2d.drawLine(columnPositions.get(i), ht, columnPositions.get(i), hb);\r
+                               }\r
+                               if (isFirstLine() || !linesPrevVisible) {\r
+                                       g2d.drawLine(0, ht, stream.contentWidth, ht);\r
+                                       linesPrevVisible = true;\r
+                               }\r
+                               g2d.drawLine(stream.contentWidth, ht, stream.contentWidth, hb);\r
+                               g2d.drawLine(0, hb, stream.contentWidth, hb);\r
+                       }\r
+                       currentLine++;\r
+                       page.currentLine++;\r
+                       page.availableLines--;\r
+                       page.currentPixel += getLineHeight();\r
+               } else {\r
+                       PositionedRow row = _getRow(line);\r
+                       if (stream.contentHeight-page.currentPixel < row.reservedSpace) {\r
+                               stream.nextPage();\r
+                               page = getCurrentPage();\r
+                               g2d = page.g2d;\r
+                               writeHeader();\r
+                               row = _getRow(line);\r
+                       }\r
+                       row.render(g2d);\r
+                       currentLine+= row.realLines;\r
+                       page.currentLine+= row.realLines;\r
+                       page.currentPixel += row.reservedSpace;\r
+                       page.estimateAvailableLines();\r
+               }\r
+               \r
+               stream.checkNextPage();\r
+               return new PDFTableRow();\r
+       }\r
+       \r
+       private TableRow _writeRow2(List<TextItem> line) throws Exception {\r
+               int h = getTextHeight();\r
+               int ht = getTopHeight();\r
+               int hb = getBottomHeight();\r
+               PDFPage page = getCurrentPage();\r
+               Graphics2D g2d = page.g2d;\r
+               Shape clip = g2d.getClip();\r
+               \r
+               if (clipText) {\r
+                       for (int i = 0; i < line.size(); i++) {\r
+                               TextItem text = line.get(i);\r
+                               if (text == null)\r
+                                       continue;\r
+                               g2d.setClip(columnPositions.get(i),ht,columnSizes.get(i),hb-ht);\r
+                               g2d.drawString(text.getText(), columnPositions.get(i)+textOffsetX, h);\r
+                               if (text instanceof URLItem) {\r
+                                       URL url = ((URLItem)text).getURL();\r
+                                       if (url != null) {\r
+                                               addLink(url, columnPositions.get(i),ht,columnSizes.get(i),hb-ht);\r
+                                       }\r
+                               }\r
+                       }\r
+                       g2d.setClip(clip);\r
+                       if (linesVisible) {\r
+                               for (int i = 0; i < line.size(); i++) {\r
+                                       g2d.drawLine(columnPositions.get(i), ht, columnPositions.get(i), hb);\r
+                               }\r
+                               if (isFirstLine() || !linesPrevVisible) {\r
+                                       g2d.drawLine(0, ht, stream.contentWidth, ht);\r
+                                       linesPrevVisible = true;\r
+                               }\r
+                               g2d.drawLine(stream.contentWidth, ht, stream.contentWidth, hb);\r
+                               g2d.drawLine(0, hb, stream.contentWidth, hb);\r
+                       }\r
+                       currentLine++;\r
+                       page.currentLine++;\r
+                       page.availableLines--;\r
+                       page.currentPixel += getLineHeight();\r
+               } else {\r
+                       PositionedRow row = _getRow2(line);\r
+                       if (stream.contentHeight-page.currentPixel < row.reservedSpace) {\r
+                               stream.nextPage();\r
+                               page = getCurrentPage();\r
+                               g2d = page.g2d;\r
+                               writeHeader();\r
+                               row = _getRow2(line);\r
+                       }\r
+                       row.render(g2d);\r
+                       currentLine+= row.realLines;\r
+                       page.currentLine+= row.realLines;\r
+                       page.currentPixel += row.reservedSpace;\r
+                       page.estimateAvailableLines();\r
+               }\r
+               \r
+               stream.checkNextPage();\r
+               return new PDFTableRow();\r
+       }\r
+       \r
+       void writeLine(String line) throws Exception{\r
+               writeLine(line, 0);\r
+       }\r
+       \r
+       void writeLine(TextItem line) throws Exception{\r
+               writeLine(line, 0);\r
+       }\r
+       \r
+       private void writeHeader() throws Exception{\r
+               if (headerVisible) {\r
+                       TextSize s = currentTextSize;\r
+                       setTextSize(TextSize.MEDIUM);\r
+                       if (title != null) {\r
+                               boolean b = linesVisible;\r
+                               setLinesVisible(false);\r
+                               writeLine(title);\r
+                               setLinesVisible(b);\r
+                       }\r
+                       _writeRow(columnNames);\r
+                       setTextSize(s);\r
+               }\r
+       }\r
+       \r
+       void writeLine(String line, int x) throws Exception{\r
+               int h = getTextHeight();\r
+               int ht = getTopHeight();\r
+               int hb = getBottomHeight();\r
+               PDFPage page = getCurrentPage();\r
+               Graphics2D g2d = page.g2d;\r
+               g2d.drawString(line, x+textOffsetX, h);\r
+               if (linesVisible) {\r
+                       if (isFirstLine() || !linesPrevVisible) {\r
+                               g2d.drawLine(0, ht, stream.contentWidth, ht);\r
+                               linesPrevVisible = true;\r
+                       }\r
+                       g2d.drawLine(0, ht, 0, hb);\r
+                       g2d.drawLine(stream.contentWidth, ht, stream.contentWidth, hb);\r
+                       g2d.drawLine(0, hb, stream.contentWidth, hb);\r
+               }\r
+               currentLine++;\r
+               page.currentLine++;\r
+               page.availableLines--;\r
+               page.currentPixel += getLineHeight();\r
+               stream.checkNextPage();\r
+       }\r
+       \r
+       void writeLine(TextItem line, int x) throws Exception{\r
+               int h = getTextHeight();\r
+               int ht = getTopHeight();\r
+               int hb = getBottomHeight();\r
+               PDFPage page = getCurrentPage();\r
+               Graphics2D g2d = page.g2d;\r
+               g2d.drawString(line.getText(), x+textOffsetX, h);\r
+               if (linesVisible) {\r
+                       if (isFirstLine() || !linesPrevVisible) {\r
+                               g2d.drawLine(0, ht, stream.contentWidth, ht);\r
+                               linesPrevVisible = true;\r
+                       }\r
+                       g2d.drawLine(0, ht, 0, hb);\r
+                       g2d.drawLine(stream.contentWidth, ht, stream.contentWidth, hb);\r
+                       g2d.drawLine(0, hb, stream.contentWidth, hb);\r
+               }\r
+               if (line instanceof URLItem) {\r
+                       URL url = ((URLItem)line).getURL();\r
+                       if (url != null) {\r
+                               addLink(url, 0,ht,stream.contentWidth,hb-ht);\r
+                       }\r
+               }\r
+               currentLine++;\r
+               page.currentLine++;\r
+               page.availableLines--;\r
+               page.currentPixel += getLineHeight();\r
+               stream.checkNextPage();\r
+       }\r
+       \r
+       int getTopHeight() {\r
+               return getTopHeight(currentLine);\r
+       }\r
+       \r
+       int getTopHeight(int line) {\r
+               return (line-currentLine)*getLineHeight()+getCurrentPage().currentPixel;\r
+       }\r
+       \r
+       int getTextHeight() {\r
+               PDFPage page = getCurrentPage();\r
+               return page.currentPixel+getLineHeight()-page.fm.getDescent()-textOffsetY;\r
+       }\r
+       \r
+       PDFPage getCurrentPage() {\r
+               return stream.getCurrentPage();\r
+       }\r
+       \r
+       int getBottomHeight() {\r
+               return getBottomHeight(currentLine);\r
+       }\r
+       \r
+       protected int getLineHeight() {\r
+               return getCurrentPage().fm.getHeight()+textOffsetY;\r
+       }\r
+       \r
+       private int getBottomHeight(int line) {\r
+               return (line-currentLine+1)*getLineHeight()+getCurrentPage().currentPixel;\r
+       }\r
+       \r
+       public int getAvailableLines() {\r
+               PDFPage page = getCurrentPage();\r
+               int contentHeight = stream.contentHeight;\r
+               int pixelY = page.currentPixel;\r
+               return (int)Math.floor((contentHeight-pixelY)/getLineHeight());\r
+       }\r
+       \r
+       private TextSize currentTextSize = TextSize.SMALL;\r
+       \r
+       @Override\r
+       public void setTextSize(TextSize size) {\r
+               stream.getCurrentPage().setFont(writer.fonts.get(size));\r
+               currentTextSize = size;\r
+       }\r
+       \r
+       @Override\r
+       public TextSize getTextSize() {\r
+               return currentTextSize;\r
+       }\r
+       \r
+       private PositionedRow _getRow(List<String> line) {\r
+               PositionedRow row = new PositionedRow();\r
+               int h = getTextHeight();\r
+               int realLines = 1;\r
+               int reservedSpace = 0;\r
+               List<List<PositionedText>> cells = new ArrayList<List<PositionedText>>(line.size());\r
+               if (line.size() > 1) {\r
+                       for (int i = 0; i < line.size(); i++) {\r
+                               String text = line.get(i);\r
+                               int availableSize = columnSizes.get(i)-textOffsetX;\r
+                               if (text != null && text.length() > 0) {\r
+                                       List<PositionedText> pt = getText(text,  columnPositions.get(i)+textOffsetX, h,availableSize, columns.get(i).getAlignment());\r
+                                       cells.add(pt);\r
+                                       reservedSpace = Math.max(reservedSpace, getResevedSpace(pt)+getLineHeight());\r
+                                       realLines = Math.max(realLines, getLineSpace(pt));\r
+                               } else {\r
+                                       cells.add(Collections.<PositionedText> emptyList());\r
+                                       reservedSpace = Math.max(reservedSpace, getLineHeight());\r
+                               }\r
+                       }\r
+               } else {\r
+                       String text = line.get(0);\r
+                       int availableSize = stream.contentWidth;\r
+                       if (text != null && text.length() > 0) {\r
+                               List<PositionedText> pt = getText(text,  textOffsetX, h,availableSize, columns.get(0).getAlignment());\r
+                               cells.add(pt);\r
+                               reservedSpace = Math.max(reservedSpace, getResevedSpace(pt)+getLineHeight());\r
+                               realLines = Math.max(realLines, getLineSpace(pt));\r
+                       } else {\r
+                               cells.add(Collections.<PositionedText> emptyList());\r
+                               reservedSpace = Math.max(reservedSpace, getLineHeight());\r
+                       }\r
+               }\r
+               row.reservedSpace = reservedSpace;\r
+               row.startLine = currentLine;\r
+               row.realLines = realLines;\r
+               row.cells = cells;\r
+               return row;\r
+       }\r
+       \r
+       private PositionedRow _getRow2(List<TextItem> line) {\r
+               PositionedRow row = new PositionedRow();\r
+               int h = getTextHeight();\r
+               int realLines = 1;\r
+               int reservedSpace = 0;\r
+               row.cells = new ArrayList<List<PositionedText>>(line.size());\r
+               row.urls = new ArrayList<URL>();\r
+               if (line.size() > 1) {\r
+                       for (int i = 0; i < line.size(); i++) {\r
+                               TextItem item =line.get(i); \r
+                               \r
+                               int availableSize = columnSizes.get(i)-textOffsetX;\r
+                               if (item != null && item.getText().length() > 0) {\r
+                                       String text = item.getText();\r
+                                       List<PositionedText> pt = getText(text,  columnPositions.get(i)+textOffsetX, h,availableSize, columns.get(i).getAlignment());\r
+                                       row.cells.add(pt);\r
+                                       reservedSpace = Math.max(reservedSpace, getResevedSpace(pt)+getLineHeight());\r
+                                       realLines = Math.max(realLines, getLineSpace(pt));\r
+                               } else {\r
+                                       row.cells.add(Collections.<PositionedText> emptyList());\r
+                                       reservedSpace = Math.max(reservedSpace, getLineHeight());\r
+                               }\r
+                               if (item instanceof URLItem) {\r
+                                       row.urls.add(((URLItem)item).getURL());\r
+                               } else {\r
+                                       row.urls.add(null);\r
+                               }\r
+                       }\r
+               \r
+               } else {\r
+                       String text = line.get(0).getText();\r
+                       int availableSize = stream.contentWidth;\r
+                       if (text != null && text.length() > 0) {\r
+                               List<PositionedText> pt = getText(text,  textOffsetX, h,availableSize, columns.get(0).getAlignment());\r
+                               row.cells.add(pt);\r
+                               reservedSpace = Math.max(reservedSpace, getResevedSpace(pt)+getLineHeight());\r
+                               realLines = Math.max(realLines, getLineSpace(pt));\r
+                       } else {\r
+                               row.cells.add(Collections.<PositionedText> emptyList());\r
+                               reservedSpace = Math.max(reservedSpace, getLineHeight());\r
+                       }\r
+               }\r
+               row.reservedSpace = reservedSpace;\r
+               row.startLine = currentLine;\r
+               row.realLines = realLines;\r
+               return row;\r
+       }\r
+       \r
+       private int getResevedSpace(List<PositionedText> pt) {\r
+               float sy = pt.get(0).drawPosY;\r
+               float ey = pt.get(pt.size()-1).drawPosY;\r
+               return (int)Math.ceil(ey-sy);\r
+       }\r
+       /**\r
+        * Usually lines of multi-line cells consume less space than the maximum line height (FontMetrics). This method calculates the exact amount of lines required by a cell. \r
+        * @param pt\r
+        * @return\r
+        */\r
+       private int getLineSpace(List<PositionedText> pt) {\r
+               if (pt.size() < 2)\r
+                       return 1;\r
+               \r
+               return (int)(getResevedSpace(pt)/getLineHeight())+1;\r
+       }\r
+       \r
+       private class PositionedRow {\r
+               int startLine;\r
+               int realLines;\r
+               int reservedSpace;\r
+               List<List<PositionedText>> cells;\r
+               List<URL> urls;\r
+               \r
+               void render(Graphics2D g) {\r
+                       int ht = getTopHeight(startLine);\r
+                       int hb = ht +reservedSpace;\r
+                       if (cells.size() > 0) {\r
+                               for (int i = 0; i < cells.size(); i++) {\r
+                                       List<PositionedText> ptl = cells.get(i);\r
+                                       for (PositionedText pt : ptl)\r
+                                               pt.render(g);\r
+                                       if (urls != null) {\r
+                                               URL url = urls.get(i);\r
+                                               if (url != null) {\r
+                                                       addLink(url, columnPositions.get(i),ht,columnSizes.get(i),hb-ht);\r
+                                               }\r
+                                       }\r
+                               }\r
+                       } \r
+                       if (linesVisible) {\r
+                               if (cells.size() > 0) {\r
+                                       for (int i = 0; i < cells.size(); i++) {\r
+                                               g.drawLine(columnPositions.get(i), ht, columnPositions.get(i), hb);\r
+                                       }\r
+                               } else {\r
+                                       g.drawLine(columnPositions.get(0), ht, columnPositions.get(0), hb);\r
+                               }\r
+                               if (isFirstLine() || !linesPrevVisible) {\r
+                                       g.drawLine(0, ht, stream.contentWidth, ht);\r
+                                       linesPrevVisible = true;\r
+                               }\r
+                               g.drawLine(stream.contentWidth, ht, stream.contentWidth, hb);\r
+                               g.drawLine(0, hb, stream.contentWidth, hb);\r
+                               \r
+                       }\r
+               }\r
+       }\r
+       \r
+       private void addLink(URL url, int x, int y, int w, int h) {\r
+               PDFPage page = getCurrentPage();\r
+               float fx = +page.stream.marginLeft + x;\r
+               float fy = -page.stream.marginTop + page.template.getHeight() - y;\r
+               page.template.setAction(new PdfAction(url), fx, fy-h, fx+w, fy);\r
+       }\r
+       \r
+       private List<PositionedText> getText(String text, int x, int y, int cellWidth, Alignment alignment) {\r
+               List<PositionedText> result = new ArrayList<PositionedText>();\r
+               Hashtable<TextAttribute, Object> map = new Hashtable<TextAttribute, Object>();\r
+               PDFPage page = getCurrentPage();\r
+               Font font = page.getFont();\r
+               for (TextAttribute a : font.getAttributes().keySet()) {\r
+                       Object v = font.getAttributes().get(a);\r
+                       if (v != null)\r
+                               map.put(a, v);\r
+               }\r
+//             map.putAll(font.getAttributes());\r
+               map.put(TextAttribute.FOREGROUND, Color.black);\r
+\r
+               AttributedString attributedText = new AttributedString( text, map);\r
+\r
+               AttributedCharacterIterator paragraph = attributedText.getIterator();\r
+               int paragraphStart = paragraph.getBeginIndex();\r
+               int paragraphEnd = paragraph.getEndIndex();\r
+               LineBreakMeasurer lineMeasurer = new LineBreakMeasurer(paragraph, page.frc);\r
+               lineMeasurer.setPosition(paragraphStart);\r
+               \r
+               // Get lines until the entire paragraph has been displayed.\r
+        int next, limit, charat, position = 0;\r
+        int drawPosY = y;\r
+        while ((position = lineMeasurer.getPosition()) < paragraphEnd) {\r
+\r
+            // Find possible line break and set it as a limit to the next layout\r
+            next = lineMeasurer.nextOffset(cellWidth);\r
+            limit = next;\r
+            charat = text.indexOf(System.getProperty("line.separator"),position+1);\r
+            if(charat < next && charat != -1){\r
+               limit = charat;\r
+            }\r
+\r
+            // Retrieve next layout. A cleverer program would also cache\r
+            // these layouts until the component is re-sized.\r
+            TextLayout layout = lineMeasurer.nextLayout(cellWidth, limit, false);\r
+\r
+               // Compute pen x position. If the paragraph is right-to-left we\r
+               // will align the TextLayouts to the right edge of the panel.\r
+               // Note: this won't occur for the English text in this sample.\r
+               // Note: drawPosX is always where the LEFT of the text is placed.\r
+               float drawPosX = 0;\r
+               switch (alignment) {\r
+                       case LEFT: \r
+                               drawPosX = layout.isLeftToRight() ? 0 : cellWidth - layout.getAdvance();\r
+                               break;\r
+                       case CENTER:\r
+                               drawPosX = (cellWidth - layout.getAdvance()) / 2;\r
+                               break;\r
+                       case RIGHT:\r
+                               drawPosX = layout.isLeftToRight() ? cellWidth - layout.getAdvance() : 0;\r
+                               break;\r
+               }\r
+               \r
+               drawPosX += x;\r
+               \r
+               // If text has been forced to vertical, align it to center\r
+//             if(breakWidth < textAreaWidth) {\r
+//                     float centerCorrection = layout.isLeftToRight() ? \r
+//                                     (float) (layout.getAdvance() / 2) : \r
+//                                             -1 * (float) (layout.getAdvance() / 2);\r
+//                     drawPosX = textAreaWidth / 2 - centerCorrection;\r
+//             }\r
+\r
+               // Stop drawing if the text won't fit\r
+//             if (breakHeight < drawPosY + layout.getDescent() + layout.getLeading()) {\r
+//                 break;\r
+//             }\r
+\r
+//             drawPosY += layout.getAscent();\r
+\r
+               // Add TextLayout at (drawPosX, drawPosY).\r
+               result.add(new PositionedText(drawPosX, drawPosY, layout));\r
+\r
+               // Move y-coordinate in preparation for next layout.\r
+               //drawPosY += layout.getDescent() + layout.getLeading();\r
+               drawPosY += layout.getDescent() + layout.getLeading() + layout.getAscent();\r
+//             drawPosY += getLineHeight();\r
+           }\r
+        return result;\r
+       }\r
+       \r
+       class PositionedText {\r
+        float drawPosX;\r
+        float drawPosY;\r
+        TextLayout layout;      \r
+        \r
+        public PositionedText(float drawPosX, float drawPosY, TextLayout layout) {\r
+            this.drawPosX = drawPosX;\r
+            this.drawPosY = drawPosY;\r
+            this.layout = layout;\r
+        }\r
+        \r
+        public void render(Graphics2D g) {\r
+            layout.draw(g, drawPosX, drawPosY);\r
+        }\r
+    }\r
+}\r