From eb1e1a28e8fe4815851b283789a2552bbac9afcb Mon Sep 17 00:00:00 2001 From: Andreas Beeker Date: Thu, 29 Oct 2015 01:05:27 +0000 Subject: [PATCH] Common sl unification - copy first paragraph / textrun properties on XSLFTextShape.setText() Common sl unification - converted ApacheconEU08 example to common sl - added missing functionality Common sl unification - return null instead of default values for missing borders X/HSLFTable Common sl unification - use points in HSLFTable.setColumnWidth() Fix appending text to empty HSLFTextParagraph git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1711171 13f79535-47bb-0310-9956-ffa450edef68 --- .../poi/hslf/examples/ApacheconEU08.java | 253 +-- .../apache/poi/hslf/examples/TableDemo.java | 18 +- .../apache/poi/xslf/usermodel/Tutorial3.java | 2 + .../apache/poi/xslf/usermodel/Tutorial4.java | 5 +- .../apache/poi/sl/draw/DrawTableShape.java | 112 + .../org/apache/poi/sl/draw/SLGraphics.java | 1831 +++++++++++++++++ .../apache/poi/sl/usermodel/SimpleShape.java | 57 +- .../apache/poi/sl/usermodel/SlideShow.java | 7 + .../apache/poi/sl/usermodel/StrokeStyle.java | 38 +- .../apache/poi/sl/usermodel/TableCell.java | 61 + .../apache/poi/sl/usermodel/TableShape.java | 22 +- .../org/apache/poi/sl/usermodel/TextBox.java | 7 + .../poi/sl/usermodel/TextParagraph.java | 6 + .../org/apache/poi/sl/usermodel/TextRun.java | 143 +- .../apache/poi/sl/usermodel/TextShape.java | 82 +- .../poi/xslf/usermodel/Placeholder.java | 41 - .../poi/xslf/usermodel/XMLSlideShow.java | 13 +- .../poi/xslf/usermodel/XSLFAutoShape.java | 21 +- .../apache/poi/xslf/usermodel/XSLFShape.java | 1 + .../apache/poi/xslf/usermodel/XSLFSheet.java | 1 + .../poi/xslf/usermodel/XSLFSimpleShape.java | 118 +- .../apache/poi/xslf/usermodel/XSLFSlide.java | 2 +- .../poi/xslf/usermodel/XSLFSlideLayout.java | 2 +- .../poi/xslf/usermodel/XSLFSlideMaster.java | 2 +- .../apache/poi/xslf/usermodel/XSLFTable.java | 15 +- .../poi/xslf/usermodel/XSLFTableCell.java | 261 ++- .../poi/xslf/usermodel/XSLFTextBox.java | 3 +- .../poi/xslf/usermodel/XSLFTextParagraph.java | 22 +- .../poi/xslf/usermodel/XSLFTextRun.java | 60 +- .../poi/xslf/usermodel/XSLFTextShape.java | 132 +- .../poi/xslf/usermodel/TestXSLFAutoShape.java | 2 +- .../poi/xslf/usermodel/TestXSLFNotes.java | 15 +- .../xslf/usermodel/TestXSLFSimpleShape.java | 8 +- .../poi/xslf/usermodel/TestXSLFTable.java | 57 +- .../poi/xslf/usermodel/TestXSLFTextBox.java | 11 +- .../poi/xslf/usermodel/TestXSLFTextShape.java | 5 +- .../apache/poi/hslf/model/PPGraphics2D.java | 4 +- .../apache/poi/hslf/model/Placeholder.java | 96 - .../poi/hslf/usermodel/HSLFAutoShape.java | 2 +- .../poi/hslf/usermodel/HSLFGroupShape.java | 85 +- .../poi/hslf/usermodel/HSLFPlaceholder.java | 55 + .../apache/poi/hslf/usermodel/HSLFShape.java | 12 +- .../poi/hslf/usermodel/HSLFShapeFactory.java | 96 +- .../apache/poi/hslf/usermodel/HSLFSheet.java | 2 +- .../poi/hslf/usermodel/HSLFSimpleShape.java | 185 +- .../apache/poi/hslf/usermodel/HSLFSlide.java | 3 +- .../poi/hslf/usermodel/HSLFSlideShow.java | 11 +- .../apache/poi/hslf/usermodel/HSLFTable.java | 427 ++-- .../poi/hslf/usermodel/HSLFTableCell.java | 323 ++- .../poi/hslf/usermodel/HSLFTextParagraph.java | 88 +- .../poi/hslf/usermodel/HSLFTextRun.java | 48 +- .../poi/hslf/usermodel/HSLFTextShape.java | 203 +- .../org/apache/poi/hslf/model/TestLine.java | 16 +- .../org/apache/poi/hslf/model/TestShapes.java | 4 +- .../org/apache/poi/hslf/model/TestTable.java | 17 +- .../apache/poi/hslf/usermodel/TestTable.java | 35 +- .../poi/hslf/usermodel/TestTextRun.java | 9 + 57 files changed, 4028 insertions(+), 1129 deletions(-) create mode 100644 src/java/org/apache/poi/sl/draw/SLGraphics.java delete mode 100644 src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java delete mode 100644 src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java create mode 100644 src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholder.java diff --git a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java index c911424726..8101c71f63 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java +++ b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java @@ -26,19 +26,20 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.List; -import org.apache.poi.hslf.model.PPGraphics2D; -import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFAutoShape; -import org.apache.poi.hslf.usermodel.HSLFGroupShape; -import org.apache.poi.hslf.usermodel.HSLFSlide; import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFTable; -import org.apache.poi.hslf.usermodel.HSLFTableCell; -import org.apache.poi.hslf.usermodel.HSLFTextBox; -import org.apache.poi.hslf.usermodel.HSLFTextParagraph; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFLine; +import org.apache.poi.sl.draw.DrawTableShape; +import org.apache.poi.sl.draw.SLGraphics; +import org.apache.poi.sl.usermodel.AutoShape; +import org.apache.poi.sl.usermodel.GroupShape; import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.sl.usermodel.Slide; +import org.apache.poi.sl.usermodel.SlideShow; +import org.apache.poi.sl.usermodel.TableCell; +import org.apache.poi.sl.usermodel.TableShape; +import org.apache.poi.sl.usermodel.TextBox; +import org.apache.poi.sl.usermodel.TextParagraph; +import org.apache.poi.sl.usermodel.TextRun; +import org.apache.poi.sl.usermodel.TextShape.TextPlaceholder; import org.apache.poi.sl.usermodel.VerticalAlignment; /** @@ -49,7 +50,8 @@ import org.apache.poi.sl.usermodel.VerticalAlignment; public final class ApacheconEU08 { public static void main(String[] args) throws IOException { - HSLFSlideShow ppt = new HSLFSlideShow(); + SlideShow ppt = new HSLFSlideShow(); + // SlideShow ppt = new XMLSlideShow(); ppt.setPageSize(new Dimension(720, 540)); slide1(ppt); @@ -65,69 +67,62 @@ public final class ApacheconEU08 { slide11(ppt); slide12(ppt); - FileOutputStream out = new FileOutputStream("apachecon_eu_08.ppt"); + String ext = ppt.getClass().getName().contains("HSLF") ? "ppt" : "pptx"; + FileOutputStream out = new FileOutputStream("apachecon_eu_08."+ext); ppt.write(out); out.close(); } - public static void slide1(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide1(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE); box1.setText("POI-HSLF"); box1.setAnchor(new Rectangle(54, 78, 612, 115)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY); box2.setText("Java API To Access Microsoft PowerPoint Format Files"); box2.setAnchor(new Rectangle(108, 204, 504, 138)); - slide.addShape(box2); - HSLFTextBox box3 = new HSLFTextBox(); + TextBox box3 = slide.createTextBox(); box3.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(32d); box3.setText( "Yegor Kozlov\r" + "yegor - apache - org"); box3.setHorizontalCentered(true); box3.setAnchor(new Rectangle(206, 348, 310, 84)); - slide.addShape(box3); } - public static void slide2(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide2(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("What is HSLF?"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.BODY); box2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " + "of the Powerpoint binary file format. \r" + "POI sub-project since 2005\r" + - "Started by Nick Birch, Yegor Kozlov joined soon after"); + "Started by Nick Burch, Yegor Kozlov joined soon after"); box2.setAnchor(new Rectangle(36, 126, 648, 356)); - slide.addShape(box2); - - } - public static void slide3(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide3(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("HSLF in a Nutshell"); box1.setAnchor(new Rectangle(36, 15, 648, 65)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.BODY); box2.setText( "HSLF provides a way to read, create and modify MS PowerPoint presentations\r" + "Pure Java API - you don't need PowerPoint to read and write *.ppt files\r" + @@ -140,7 +135,7 @@ public final class ApacheconEU08 { "Access to low level data structures" ); - List tp = box2.getTextParagraphs(); + List> tp = box2.getTextParagraphs(); for (int i : new byte[]{0,1,2,8}) { tp.get(i).getTextRuns().get(0).setFontSize(28d); } @@ -149,102 +144,88 @@ public final class ApacheconEU08 { tp.get(i).setIndentLevel(1); } box2.setAnchor(new Rectangle(36, 80, 648, 400)); - slide.addShape(box2); } - public static void slide4(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide4(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); String[][] txt1 = { {"Note"}, {"This presentation was created programmatically using POI HSLF"} }; - HSLFTable table1 = new HSLFTable(2, 1); + TableShape table1 = slide.createTable(2, 1); for (int i = 0; i < txt1.length; i++) { for (int j = 0; j < txt1[i].length; j++) { - HSLFTableCell cell = table1.getCell(i, j); + TableCell cell = table1.getCell(i, j); cell.setText(txt1[i][j]); - HSLFTextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0); + TextRun rt = cell.getTextParagraphs().get(0).getTextRuns().get(0); rt.setFontSize(10d); rt.setFontFamily("Arial"); rt.setBold(true); if(i == 0){ rt.setFontSize(32d); rt.setFontColor(Color.white); - cell.getFill().setForegroundColor(new Color(0, 153, 204)); + cell.setFillColor(new Color(0, 153, 204)); } else { rt.setFontSize(28d); - cell.getFill().setForegroundColor(new Color(235, 239, 241)); + cell.setFillColor(new Color(235, 239, 241)); } cell.setVerticalAlignment(VerticalAlignment.MIDDLE); } } - HSLFLine border1 = table1.createBorder(); - border1.setLineColor(Color.black); - border1.setLineWidth(1.0); - table1.setAllBorders(border1); - - HSLFLine border2 = table1.createBorder(); - border2.setLineColor(Color.black); - border2.setLineWidth(2.0); - table1.setOutsideBorders(border2); + DrawTableShape dts = new DrawTableShape(table1); + dts.setAllBorders(1.0, Color.black); + dts.setOutsideBorders(4.0); - table1.setColumnWidth(0, 510); - table1.setRowHeight(0, 60); - table1.setRowHeight(1, 100); - slide.addShape(table1); + table1.setColumnWidth(0, 450); + table1.setRowHeight(0, 50); + table1.setRowHeight(1, 80); - table1.moveTo(100, 100); + Dimension dim = ppt.getPageSize(); + Rectangle oldAnchor = table1.getAnchor(); + table1.setAnchor(new Rectangle((dim.width-450)/2, 100, oldAnchor.width, oldAnchor.height)); - HSLFTextBox box1 = new HSLFTextBox(); + TextBox box1 = slide.createTextBox(); box1.setHorizontalCentered(true); box1.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(24d); box1.setText("The source code is available at\r" + "http://people.apache.org/~yegor/apachecon_eu08/"); box1.setAnchor(new Rectangle(80, 356, 553, 65)); - slide.addShape(box1); - } - public static void slide5(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide5(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("HSLF in Action - 1\rData Extraction"); box1.setAnchor(new Rectangle(36, 21, 648, 100)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.BODY); box2.setText( "Text from slides and notes\r" + "Images\r" + "Shapes and their properties (type, position in the slide, color, font, etc.)"); box2.setAnchor(new Rectangle(36, 150, 648, 300)); - slide.addShape(box2); - - } - public static void slide6(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide6(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("HSLF in Action - 2"); box1.setAnchor(new Rectangle(36, 20, 648, 90)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); + TextBox box2 = slide.createTextBox(); box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d); box2.setText("Creating a simple presentation from scratch"); box2.setAnchor(new Rectangle(170, 100, 364, 30)); - slide.addShape(box2); - HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0); + TextBox box3 = slide.createTextBox(); + TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0); rt3.setFontFamily("Courier New"); rt3.setFontSize(8d); box3.setText( @@ -283,77 +264,67 @@ public final class ApacheconEU08 { "out.close();"); box3.setAnchor(new Rectangle(30, 150, 618, 411)); box3.setHorizontalCentered(true); - slide.addShape(box3); } - public static void slide7(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide7(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box2 = new HSLFTextBox(); + TextBox box2 = slide.createTextBox(); box2.setHorizontalCentered(true); box2.setVerticalAlignment(VerticalAlignment.MIDDLE); box2.setText("Java Code"); - box2.getFill().setForegroundColor(new Color(187, 224, 227)); - box2.setLineColor(Color.black); - box2.setLineWidth(0.75); + box2.setFillColor(new Color(187, 224, 227)); + box2.setStrokeStyle(0.75, Color.black); box2.setAnchor(new Rectangle(66, 243, 170, 170)); - slide.addShape(box2); - HSLFTextBox box3 = new HSLFTextBox(); + TextBox box3 = slide.createTextBox(); box3.setHorizontalCentered(true); box3.setVerticalAlignment(VerticalAlignment.MIDDLE); box3.setText("*.ppt file"); - box3.setLineWidth(0.75); - box3.setLineColor(Color.black); - box3.getFill().setForegroundColor(new Color(187, 224, 227)); + box3.setFillColor(new Color(187, 224, 227)); + box3.setStrokeStyle(0.75, Color.black); box3.setAnchor(new Rectangle(473, 243, 170, 170)); - slide.addShape(box3); - HSLFAutoShape box4 = new HSLFAutoShape(ShapeType.RIGHT_ARROW); - box4.getFill().setForegroundColor(new Color(187, 224, 227)); - box4.setLineWidth(0.75); - box4.setLineColor(Color.black); + AutoShape box4 = slide.createAutoShape(); + box4.setShapeType(ShapeType.RIGHT_ARROW); + box4.setFillColor(new Color(187, 224, 227)); + box4.setStrokeStyle(0.75, Color.black); box4.setAnchor(new Rectangle(253, 288, 198, 85)); - slide.addShape(box4); } - public static void slide8(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide8(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("Wait, there is more!"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.BODY); box2.setText( "Rich text\r" + "Tables\r" + "Pictures (JPEG, PNG, BMP, WMF, PICT)\r" + "Comprehensive formatting features"); box2.setAnchor(new Rectangle(36, 126, 648, 356)); - slide.addShape(box2); } - public static void slide9(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide9(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("HSLF in Action - 3"); box1.setAnchor(new Rectangle(36, 20, 648, 50)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); + TextBox box2 = slide.createTextBox(); box2.getTextParagraphs().get(0).getTextRuns().get(0).setFontSize(18d); box2.setText("PPGraphics2D: PowerPoint Graphics2D driver"); box2.setAnchor(new Rectangle(178, 70, 387, 30)); - slide.addShape(box2); - HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0); + TextBox box3 = slide.createTextBox(); + TextRun rt3 = box3.getTextParagraphs().get(0).getTextRuns().get(0); rt3.setFontFamily("Courier New"); rt3.setFontSize(8d); box3.setText( @@ -397,10 +368,9 @@ public final class ApacheconEU08 { "out.close();"); box3.setAnchor(new Rectangle(96, 110, 499, 378)); box3.setHorizontalCentered(true); - slide.addShape(box3); } - public static void slide10(HSLFSlideShow ppt) throws IOException { + public static void slide10(SlideShow ppt) throws IOException { //bar chart data. The first value is the bar color, the second is the width Object[] def = new Object[]{ Color.yellow, new Integer(100), @@ -409,14 +379,13 @@ public final class ApacheconEU08 { Color.red, new Integer(200), }; - HSLFSlide slide = ppt.createSlide(); + Slide slide = ppt.createSlide(); - HSLFGroupShape group = new HSLFGroupShape(); + GroupShape group = slide.createGroup(); //define position of the drawing in the slide Rectangle bounds = new java.awt.Rectangle(200, 100, 350, 300); group.setAnchor(bounds); - slide.addShape(group); - Graphics2D graphics = new PPGraphics2D(group); + Graphics2D graphics = new SLGraphics(group); //draw a simple bar graph int x = bounds.x + 50, y = bounds.y + 50; @@ -437,17 +406,16 @@ public final class ApacheconEU08 { } - public static void slide11(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide11(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.TITLE); box1.setText("HSLF Development Plans"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.BODY); box2.setText( "Support for more PowerPoint functionality\r" + "Rendering slides into java.awt.Graphics2D\r" + @@ -457,7 +425,7 @@ public final class ApacheconEU08 { "PPT2PDF transcoder" ); - List tp = box2.getTextParagraphs(); + List> tp = box2.getTextParagraphs(); for (int i : new byte[]{0,1,3}) { tp.get(i).getTextRuns().get(0).setFontSize(28d); } @@ -467,24 +435,21 @@ public final class ApacheconEU08 { } box2.setAnchor(new Rectangle(36, 126, 648, 400)); - slide.addShape(box2); } - public static void slide12(HSLFSlideShow ppt) throws IOException { - HSLFSlide slide = ppt.createSlide(); + public static void slide12(SlideShow ppt) throws IOException { + Slide slide = ppt.createSlide(); - HSLFTextBox box1 = new HSLFTextBox(); - box1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); + TextBox box1 = slide.createTextBox(); + box1.setTextPlaceholder(TextPlaceholder.CENTER_TITLE); box1.setText("Questions?"); box1.setAnchor(new Rectangle(54, 167, 612, 115)); - slide.addShape(box1); - HSLFTextBox box2 = new HSLFTextBox(); - box2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); + TextBox box2 = slide.createTextBox(); + box2.setTextPlaceholder(TextPlaceholder.CENTER_BODY); box2.setText( "http://poi.apache.org/hslf/\r" + "http://people.apache.org/~yegor"); box2.setAnchor(new Rectangle(108, 306, 504, 138)); - slide.addShape(box2); } } diff --git a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java index d50855e619..c8a1395902 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java @@ -25,7 +25,7 @@ import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.usermodel.HSLFTable; import org.apache.poi.hslf.usermodel.HSLFTableCell; import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFLine; +import org.apache.poi.sl.draw.DrawTableShape; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.VerticalAlignment; @@ -53,7 +53,7 @@ public final class TableDemo { HSLFSlide slide = ppt.createSlide(); //six rows, two columns - HSLFTable table1 = new HSLFTable(6, 2); + HSLFTable table1 = slide.createTable(6, 2); for (int i = 0; i < txt1.length; i++) { for (int j = 0; j < txt1[i].length; j++) { HSLFTableCell cell = table1.getCell(i, j); @@ -71,15 +71,12 @@ public final class TableDemo { } } - HSLFLine border1 = table1.createBorder(); - border1.setLineColor(Color.black); - border1.setLineWidth(1.0); - table1.setAllBorders(border1); + DrawTableShape dts1 = new DrawTableShape(table1); + dts1.setAllBorders(1.0, Color.black); table1.setColumnWidth(0, 300); table1.setColumnWidth(1, 150); - slide.addShape(table1); int pgWidth = ppt.getPageSize().width; table1.moveTo((pgWidth - table1.getAnchor().width)/2, 100); @@ -92,7 +89,7 @@ public final class TableDemo { }; //two rows, one column - HSLFTable table2 = new HSLFTable(2, 1); + HSLFTable table2 = slide.createTable(2, 1); for (int i = 0; i < txt2.length; i++) { for (int j = 0; j < txt2[i].length; j++) { HSLFTableCell cell = table2.getCell(i, j); @@ -119,10 +116,9 @@ public final class TableDemo { table2.setRowHeight(0, 30); table2.setRowHeight(1, 70); - HSLFLine border2 = table2.createBorder(); - table2.setOutsideBorders(border2); + DrawTableShape dts2 = new DrawTableShape(table2); + dts2.setOutsideBorders(Color.black, 1.0); - slide.addShape(table2); table2.moveTo(200, 400); FileOutputStream out = new FileOutputStream("hslf-table.ppt"); diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java index 54347b4c32..28c1fa3f12 100644 --- a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java +++ b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java @@ -23,6 +23,8 @@ import java.awt.Rectangle; import java.io.FileOutputStream; import java.io.IOException; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; + /** * How to set slide title * diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java index ecfc986670..94082a2ef9 100644 --- a/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java +++ b/src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java @@ -24,6 +24,7 @@ import java.awt.Rectangle; import java.io.FileOutputStream; import java.io.IOException; +import org.apache.poi.sl.usermodel.TableCell.BorderEdge; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; /** @@ -56,8 +57,8 @@ public class Tutorial4 { r.setBold(true); r.setFontColor(Color.white); th.setFillColor(new Color(79, 129, 189)); - th.setBorderBottom(2); - th.setBorderBottomColor(Color.white); + th.setBorderWidth(BorderEdge.bottom, 2.0); + th.setBorderColor(BorderEdge.bottom, Color.white); tbl.setColumnWidth(i, 150); // all columns are equally sized } diff --git a/src/java/org/apache/poi/sl/draw/DrawTableShape.java b/src/java/org/apache/poi/sl/draw/DrawTableShape.java index b252ddfda9..ec44d17d6b 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTableShape.java +++ b/src/java/org/apache/poi/sl/draw/DrawTableShape.java @@ -17,9 +17,15 @@ package org.apache.poi.sl.draw; +import java.awt.Color; import java.awt.Graphics2D; import org.apache.poi.sl.usermodel.GroupShape; +import org.apache.poi.sl.usermodel.StrokeStyle; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; +import org.apache.poi.sl.usermodel.TableCell; +import org.apache.poi.sl.usermodel.TableCell.BorderEdge; import org.apache.poi.sl.usermodel.TableShape; public class DrawTableShape extends DrawShape { @@ -57,5 +63,111 @@ public class DrawTableShape extends DrawShape { } } + @Override + protected TableShape getShape() { + return (TableShape)shape; + } + + /** + * Format the table and apply the specified Line to all cell boundaries, + * both outside and inside. + * An empty args parameter removes the affected border. + * + * @param args a varargs array possible containing {@link Double} (width), + * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash} + */ + public void setAllBorders(Object... args) { + TableShape table = getShape(); + final int rows = table.getNumberOfRows(); + final int cols = table.getNumberOfColumns(); + + BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null }; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + edges[2] = (col == cols - 1) ? BorderEdge.right : null; + edges[3] = (row == rows - 1) ? BorderEdge.bottom : null; + setEdges(table.getCell(row, col), edges, args); + } + } + } + + /** + * Format the outside border using the specified Line object + * An empty args parameter removes the affected border. + * + * @param args a varargs array possible containing {@link Double} (width), + * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash} + */ + public void setOutsideBorders(Object... args){ + if (args.length == 0) return; + + TableShape table = getShape(); + final int rows = table.getNumberOfRows(); + final int cols = table.getNumberOfColumns(); + + BorderEdge edges[] = new BorderEdge[4]; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + edges[0] = (col == 0) ? BorderEdge.left : null; + edges[1] = (col == cols - 1) ? BorderEdge.right : null; + edges[2] = (row == 0) ? BorderEdge.top : null; + edges[3] = (row == rows - 1) ? BorderEdge.bottom : null; + setEdges(table.getCell(row, col), edges, args); + } + } + } + + /** + * Format the inside border using the specified Line object + * An empty args parameter removes the affected border. + * + * @param args a varargs array possible containing {@link Double} (width), + * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash} + */ + public void setInsideBorders(Object... args) { + if (args.length == 0) return; + + TableShape table = getShape(); + final int rows = table.getNumberOfRows(); + final int cols = table.getNumberOfColumns(); + + BorderEdge edges[] = new BorderEdge[2]; + for (int row = 0; row < rows; row++) { + for (int col = 0; col < cols; col++) { + edges[0] = (col > 0 && col < cols - 1) ? BorderEdge.right : null; + edges[1] = (row > 0 && row < rows - 1) ? BorderEdge.bottom : null; + setEdges(table.getCell(row, col), edges, args); + } + } + } + + /** + * Apply the border attributes (args) to the given cell and edges + * + * @param cell the cell + * @param edges the border edges + * @param args the border attributes + */ + private static void setEdges(TableCell cell, BorderEdge edges[], Object... args) { + for (BorderEdge be : edges) { + if (be != null) { + if (args.length == 0) { + cell.removeBorder(be); + } else { + for (Object o : args) { + if (o instanceof Double) { + cell.setBorderWidth(be, (Double)o); + } else if (o instanceof Color) { + cell.setBorderColor(be, (Color)o); + } else if (o instanceof LineDash) { + cell.setBorderDash(be, (LineDash)o); + } else if (o instanceof LineCompound) { + cell.setBorderCompound(be, (LineCompound)o); + } + } + } + } + } + } } diff --git a/src/java/org/apache/poi/sl/draw/SLGraphics.java b/src/java/org/apache/poi/sl/draw/SLGraphics.java new file mode 100644 index 0000000000..2a6d884ca1 --- /dev/null +++ b/src/java/org/apache/poi/sl/draw/SLGraphics.java @@ -0,0 +1,1831 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.sl.draw; + + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +import org.apache.poi.sl.usermodel.FreeformShape; +import org.apache.poi.sl.usermodel.GroupShape; +import org.apache.poi.sl.usermodel.Insets2D; +import org.apache.poi.sl.usermodel.SimpleShape; +import org.apache.poi.sl.usermodel.StrokeStyle; +import org.apache.poi.sl.usermodel.TextBox; +import org.apache.poi.sl.usermodel.TextRun; +import org.apache.poi.sl.usermodel.VerticalAlignment; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; +import org.apache.poi.util.SuppressForbidden; + +/** + * Translates Graphics2D calls into PowerPoint. + * + * @author Yegor Kozlov + */ +public final class SLGraphics extends Graphics2D implements Cloneable { + + protected POILogger log = POILogFactory.getLogger(this.getClass()); + + //The ppt object to write into. + private GroupShape _group; + + private AffineTransform _transform; + private Stroke _stroke; + private Paint _paint; + private Font _font; + private Color _foreground; + private Color _background; + private RenderingHints _hints; + + /** + * Construct Java Graphics object which translates graphic calls in ppt drawing layer. + * + * @param group The shape group to write the graphics calls into. + */ + public SLGraphics(GroupShape group){ + this._group = group; + + _transform = new AffineTransform(); + _stroke = new BasicStroke(); + _paint = Color.black; + _font = new Font("Arial", Font.PLAIN, 12); + _background = Color.black; + _foreground = Color.white; + _hints = new RenderingHints(null); + } + + /** + * @return the shape group being used for drawing + */ + public GroupShape getShapeGroup(){ + return _group; + } + + /** + * Gets the current font. + * @return this graphics context's current font. + * @see java.awt.Font + * @see java.awt.Graphics#setFont(Font) + */ + public Font getFont(){ + return _font; + } + + /** + * Sets this graphics context's font to the specified font. + * All subsequent text operations using this graphics context + * use this font. + * @param font the font. + * @see java.awt.Graphics#getFont + * @see java.awt.Graphics#drawString(java.lang.String, int, int) + * @see java.awt.Graphics#drawBytes(byte[], int, int, int, int) + * @see java.awt.Graphics#drawChars(char[], int, int, int, int) + */ + public void setFont(Font font){ + this._font = font; + } + + /** + * Gets this graphics context's current color. + * @return this graphics context's current color. + * @see java.awt.Color + * @see java.awt.Graphics#setColor + */ + public Color getColor(){ + return _foreground; + } + + /** + * Sets this graphics context's current color to the specified + * color. All subsequent graphics operations using this graphics + * context use this specified color. + * @param c the new rendering color. + * @see java.awt.Color + * @see java.awt.Graphics#getColor + */ + public void setColor(Color c) { + setPaint(c); + } + + /** + * Returns the current Stroke in the + * Graphics2D context. + * @return the current Graphics2D Stroke, + * which defines the line style. + * @see #setStroke + */ + public Stroke getStroke(){ + return _stroke; + } + + /** + * Sets the Stroke for the Graphics2D context. + * @param s the Stroke object to be used to stroke a + * Shape during the rendering process + */ + public void setStroke(Stroke s){ + this._stroke = s; + } + + /** + * Returns the current Paint of the + * Graphics2D context. + * @return the current Graphics2D Paint, + * which defines a color or pattern. + * @see #setPaint + * @see java.awt.Graphics#setColor + */ + public Paint getPaint(){ + return _paint; + } + + /** + * Sets the Paint attribute for the + * Graphics2D context. Calling this method + * with a null Paint object does + * not have any effect on the current Paint attribute + * of this Graphics2D. + * @param paint the Paint object to be used to generate + * color during the rendering process, or null + * @see java.awt.Graphics#setColor + */ + public void setPaint(Paint paint){ + if(paint == null) return; + + this._paint = paint; + if (paint instanceof Color) _foreground = (Color)paint; + } + + /** + * Returns a copy of the current Transform in the + * Graphics2D context. + * @return the current AffineTransform in the + * Graphics2D context. + * @see #_transform + * @see #setTransform + */ + public AffineTransform getTransform(){ + return new AffineTransform(_transform); + } + + /** + * Sets the Transform in the Graphics2D + * context. + * @param Tx the AffineTransform object to be used in the + * rendering process + * @see #_transform + * @see AffineTransform + */ + public void setTransform(AffineTransform Tx) { + _transform = new AffineTransform(Tx); + } + + /** + * Strokes the outline of a Shape using the settings of the + * current Graphics2D context. The rendering attributes + * applied include the Clip, Transform, + * Paint, Composite and + * Stroke attributes. + * @param shape the Shape to be rendered + * @see #setStroke + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #_transform + * @see #setTransform + * @see #clip + * @see #setClip + * @see #setComposite + */ + public void draw(Shape shape){ + GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape)); + FreeformShape p = _group.createFreeform(); + p.setPath(path); + p.setFillColor(null); + applyStroke(p); + if (_paint instanceof Color) { + p.setStrokeStyle((Color)_paint); + } + } + + /** + * Renders the text specified by the specified String, + * using the current text attribute state in the Graphics2D context. + * The baseline of the first character is at position + * (xy) in the User Space. + * The rendering attributes applied include the Clip, + * Transform, Paint, Font and + * Composite attributes. For characters in script systems + * such as Hebrew and Arabic, the glyphs can be rendered from right to + * left, in which case the coordinate supplied is the location of the + * leftmost character on the baseline. + * @param s the String to be rendered + * @param x the x coordinate of the location where the + * String should be rendered + * @param y the y coordinate of the location where the + * String should be rendered + * @throws NullPointerException if str is + * null + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see java.awt.Graphics#setFont + * @see #setTransform + * @see #setComposite + * @see #setClip + */ + public void drawString(String s, float x, float y) { + TextBox txt = _group.createTextBox(); + + TextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0); + rt.setFontSize((double)_font.getSize()); + rt.setFontFamily(_font.getFamily()); + + if (getColor() != null) rt.setFontColor(DrawPaint.createSolidPaint(getColor())); + if (_font.isBold()) rt.setBold(true); + if (_font.isItalic()) rt.setItalic(true); + + txt.setText(s); + + txt.setInsets(new Insets2D(0,0,0,0)); + txt.setWordWrap(false); + txt.setHorizontalCentered(false); + txt.setVerticalAlignment(VerticalAlignment.MIDDLE); + + + TextLayout layout = new TextLayout(s, _font, getFontRenderContext()); + float ascent = layout.getAscent(); + + float width = (float) Math.floor(layout.getAdvance()); + /** + * Even if top and bottom margins are set to 0 PowerPoint + * always sets extra space between the text and its bounding box. + * + * The approximation height = ascent*2 works good enough in most cases + */ + float height = ascent * 2; + + /* + In powerpoint anchor of a shape is its top left corner. + Java graphics sets string coordinates by the baseline of the first character + so we need to shift up by the height of the textbox + */ + y -= height / 2 + ascent / 2; + + /* + In powerpoint anchor of a shape is its top left corner. + Java graphics sets string coordinates by the baseline of the first character + so we need to shift down by the height of the textbox + */ + txt.setAnchor(new Rectangle((int)x, (int)y, (int)width, (int)height)); + } + + /** + * Fills the interior of a Shape using the settings of the + * Graphics2D context. The rendering attributes applied + * include the Clip, Transform, + * Paint, and Composite. + * @param shape the Shape to be filled + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #_transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + */ + public void fill(Shape shape){ + GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape)); + FreeformShape p = _group.createFreeform(); + p.setPath(path); + applyPaint(p); + p.setStrokeStyle(); //Fills must be "No Line" + } + + /** + * Translates the origin of the graphics context to the point + * (xy) in the current coordinate system. + * Modifies this graphics context so that its new origin corresponds + * to the point (xy) in this graphics context's + * original coordinate system. All coordinates used in subsequent + * rendering operations on this graphics context will be relative + * to this new origin. + * @param x the x coordinate. + * @param y the y coordinate. + */ + public void translate(int x, int y){ + _transform.translate(x, y); + } + + /** + * Intersects the current Clip with the interior of the + * specified Shape and sets the Clip to the + * resulting intersection. The specified Shape is + * transformed with the current Graphics2D + * Transform before being intersected with the current + * Clip. This method is used to make the current + * Clip smaller. + * To make the Clip larger, use setClip. + * The user clip modified by this method is independent of the + * clipping associated with device bounds and visibility. If no clip has + * previously been set, or if the clip has been cleared using + * {@link java.awt.Graphics#setClip(Shape) setClip} with a + * null argument, the specified Shape becomes + * the new user clip. + * @param s the Shape to be intersected with the current + * Clip. If s is null, + * this method clears the current Clip. + */ + public void clip(Shape s){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Gets the current clipping area. + * This method returns the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * If no clip has previously been set, or if the clip has been + * cleared using setClip(null), this method returns + * null. + * @return a Shape object representing the + * current clipping area, or null if + * no clip is set. + * @see java.awt.Graphics#getClipBounds() + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @see java.awt.Graphics#setClip(Shape) + * @since JDK1.1 + */ + public Shape getClip(){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return null; + } + + /** + * Concatenates the current Graphics2D + * Transform with a scaling transformation + * Subsequent rendering is resized according to the specified scaling + * factors relative to the previous scaling. + * This is equivalent to calling transform(S), where S is an + * AffineTransform represented by the following matrix: + *
+     *          [   sx   0    0   ]
+     *          [   0    sy   0   ]
+     *          [   0    0    1   ]
+     * 
+ * @param sx the amount by which X coordinates in subsequent + * rendering operations are multiplied relative to previous + * rendering operations. + * @param sy the amount by which Y coordinates in subsequent + * rendering operations are multiplied relative to previous + * rendering operations. + */ + public void scale(double sx, double sy){ + _transform.scale(sx, sy); + } + + /** + * Draws an outlined round-cornered rectangle using this graphics + * context's current color. The left and right edges of the rectangle + * are at x and x + width, + * respectively. The top and bottom edges of the rectangle are at + * y and y + height. + * @param x the x coordinate of the rectangle to be drawn. + * @param y the y coordinate of the rectangle to be drawn. + * @param width the width of the rectangle to be drawn. + * @param height the height of the rectangle to be drawn. + * @param arcWidth the horizontal diameter of the arc + * at the four corners. + * @param arcHeight the vertical diameter of the arc + * at the four corners. + * @see java.awt.Graphics#fillRoundRect + */ + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight){ + RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight); + draw(rect); + } + + /** + * Draws the text given by the specified string, using this + * graphics context's current font and color. The baseline of the + * first character is at position (xy) in this + * graphics context's coordinate system. + * @param str the string to be drawn. + * @param x the x coordinate. + * @param y the y coordinate. + * @see java.awt.Graphics#drawBytes + * @see java.awt.Graphics#drawChars + */ + public void drawString(String str, int x, int y){ + drawString(str, (float)x, (float)y); + } + + /** + * Fills an oval bounded by the specified rectangle with the + * current color. + * @param x the x coordinate of the upper left corner + * of the oval to be filled. + * @param y the y coordinate of the upper left corner + * of the oval to be filled. + * @param width the width of the oval to be filled. + * @param height the height of the oval to be filled. + * @see java.awt.Graphics#drawOval + */ + public void fillOval(int x, int y, int width, int height){ + Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); + fill(oval); + } + + /** + * Fills the specified rounded corner rectangle with the current color. + * The left and right edges of the rectangle + * are at x and x + width - 1, + * respectively. The top and bottom edges of the rectangle are at + * y and y + height - 1. + * @param x the x coordinate of the rectangle to be filled. + * @param y the y coordinate of the rectangle to be filled. + * @param width the width of the rectangle to be filled. + * @param height the height of the rectangle to be filled. + * @param arcWidth the horizontal diameter + * of the arc at the four corners. + * @param arcHeight the vertical diameter + * of the arc at the four corners. + * @see java.awt.Graphics#drawRoundRect + */ + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight){ + + RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight); + fill(rect); + } + + /** + * Fills a circular or elliptical arc covering the specified rectangle. + *

+ * The resulting arc begins at startAngle and extends + * for arcAngle degrees. + * Angles are interpreted such that 0 degrees + * is at the 3 o'clock position. + * A positive value indicates a counter-clockwise rotation + * while a negative value indicates a clockwise rotation. + *

+ * The center of the arc is the center of the rectangle whose origin + * is (xy) and whose size is specified by the + * width and height arguments. + *

+ * The resulting arc covers an area + * width + 1 pixels wide + * by height + 1 pixels tall. + *

+ * The angles are specified relative to the non-square extents of + * the bounding rectangle such that 45 degrees always falls on the + * line from the center of the ellipse to the upper right corner of + * the bounding rectangle. As a result, if the bounding rectangle is + * noticeably longer in one axis than the other, the angles to the + * start and end of the arc segment will be skewed farther along the + * longer axis of the bounds. + * @param x the x coordinate of the + * upper-left corner of the arc to be filled. + * @param y the y coordinate of the + * upper-left corner of the arc to be filled. + * @param width the width of the arc to be filled. + * @param height the height of the arc to be filled. + * @param startAngle the beginning angle. + * @param arcAngle the angular extent of the arc, + * relative to the start angle. + * @see java.awt.Graphics#drawArc + */ + public void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle){ + Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.PIE); + fill(arc); + } + + /** + * Draws the outline of a circular or elliptical arc + * covering the specified rectangle. + *

+ * The resulting arc begins at startAngle and extends + * for arcAngle degrees, using the current color. + * Angles are interpreted such that 0 degrees + * is at the 3 o'clock position. + * A positive value indicates a counter-clockwise rotation + * while a negative value indicates a clockwise rotation. + *

+ * The center of the arc is the center of the rectangle whose origin + * is (xy) and whose size is specified by the + * width and height arguments. + *

+ * The resulting arc covers an area + * width + 1 pixels wide + * by height + 1 pixels tall. + *

+ * The angles are specified relative to the non-square extents of + * the bounding rectangle such that 45 degrees always falls on the + * line from the center of the ellipse to the upper right corner of + * the bounding rectangle. As a result, if the bounding rectangle is + * noticeably longer in one axis than the other, the angles to the + * start and end of the arc segment will be skewed farther along the + * longer axis of the bounds. + * @param x the x coordinate of the + * upper-left corner of the arc to be drawn. + * @param y the y coordinate of the + * upper-left corner of the arc to be drawn. + * @param width the width of the arc to be drawn. + * @param height the height of the arc to be drawn. + * @param startAngle the beginning angle. + * @param arcAngle the angular extent of the arc, + * relative to the start angle. + * @see java.awt.Graphics#fillArc + */ + public void drawArc(int x, int y, int width, int height, + int startAngle, int arcAngle) { + Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN); + draw(arc); + } + + + /** + * Draws a sequence of connected lines defined by + * arrays of x and y coordinates. + * Each pair of (xy) coordinates defines a point. + * The figure is not closed if the first point + * differs from the last point. + * @param xPoints an array of x points + * @param yPoints an array of y points + * @param nPoints the total number of points + * @see java.awt.Graphics#drawPolygon(int[], int[], int) + * @since JDK1.1 + */ + public void drawPolyline(int[] xPoints, int[] yPoints, + int nPoints){ + if(nPoints > 0){ + GeneralPath path = new GeneralPath(); + path.moveTo(xPoints[0], yPoints[0]); + for(int i=1; ix, y, + * width, and height arguments. + *

+ * The oval covers an area that is + * width + 1 pixels wide + * and height + 1 pixels tall. + * @param x the x coordinate of the upper left + * corner of the oval to be drawn. + * @param y the y coordinate of the upper left + * corner of the oval to be drawn. + * @param width the width of the oval to be drawn. + * @param height the height of the oval to be drawn. + * @see java.awt.Graphics#fillOval + */ + public void drawOval(int x, int y, int width, int height){ + Ellipse2D oval = new Ellipse2D.Float(x, y, width, height); + draw(oval); + } + + /** + * Draws as much of the specified image as is currently available. + * The image is drawn with its top-left corner at + * (xy) in this graphics context's coordinate + * space. Transparent pixels are drawn in the specified + * background color. + *

+ * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + *

+ * This method returns immediately in all cases, even if the + * complete image has not yet been loaded, and it has not been dithered + * and converted for the current output device. + *

+ * If the image has not yet been completely loaded, then + * drawImage returns false. As more of + * the image becomes available, the process that draws the image notifies + * the specified image observer. + * @param img the specified image to be drawn. + * @param x the x coordinate. + * @param y the y coordinate. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of + * the image is converted. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, + Color bgcolor, + ImageObserver observer){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + + return false; + } + + /** + * Draws as much of the specified image as has already been scaled + * to fit inside the specified rectangle. + *

+ * The image is drawn inside the specified rectangle of this + * graphics context's coordinate space, and is scaled if + * necessary. Transparent pixels are drawn in the specified + * background color. + * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + *

+ * This method returns immediately in all cases, even if the + * entire image has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * drawImage returns false. As more of + * the image becomes available, the process that draws the image notifies + * the specified image observer. + *

+ * A scaled version of an image will not necessarily be + * available immediately just because an unscaled version of the + * image has been constructed for this output device. Each size of + * the image may be cached separately and generated from the original + * data in a separate image production sequence. + * @param img the specified image to be drawn. + * @param x the x coordinate. + * @param y the y coordinate. + * @param width the width of the rectangle. + * @param height the height of the rectangle. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of + * the image is converted. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, + int width, int height, + Color bgcolor, + ImageObserver observer){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + + return false; + } + + + /** + * Draws as much of the specified area of the specified image as is + * currently available, scaling it on the fly to fit inside the + * specified area of the destination drawable surface. Transparent pixels + * do not affect whatever pixels are already there. + *

+ * This method returns immediately in all cases, even if the + * image area to be drawn has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * drawImage returns false. As more of + * the image becomes available, the process that draws the image notifies + * the specified image observer. + *

+ * This method always uses the unscaled version of the image + * to render the scaled rectangle and performs the required + * scaling on the fly. It does not use a cached, scaled version + * of the image for this operation. Scaling of the image from source + * to destination is performed such that the first coordinate + * of the source rectangle is mapped to the first coordinate of + * the destination rectangle, and the second source coordinate is + * mapped to the second destination coordinate. The subimage is + * scaled and flipped as needed to preserve those mappings. + * @param img the specified image to be drawn + * @param dx1 the x coordinate of the first corner of the + * destination rectangle. + * @param dy1 the y coordinate of the first corner of the + * destination rectangle. + * @param dx2 the x coordinate of the second corner of the + * destination rectangle. + * @param dy2 the y coordinate of the second corner of the + * destination rectangle. + * @param sx1 the x coordinate of the first corner of the + * source rectangle. + * @param sy1 the y coordinate of the first corner of the + * source rectangle. + * @param sx2 the x coordinate of the second corner of the + * source rectangle. + * @param sy2 the y coordinate of the second corner of the + * source rectangle. + * @param observer object to be notified as more of the image is + * scaled and converted. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + * @since JDK1.1 + */ + public boolean drawImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return false; + } + + /** + * Draws as much of the specified area of the specified image as is + * currently available, scaling it on the fly to fit inside the + * specified area of the destination drawable surface. + *

+ * Transparent pixels are drawn in the specified background color. + * This operation is equivalent to filling a rectangle of the + * width and height of the specified image with the given color and then + * drawing the image on top of it, but possibly more efficient. + *

+ * This method returns immediately in all cases, even if the + * image area to be drawn has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete then + * drawImage returns false. As more of + * the image becomes available, the process that draws the image notifies + * the specified image observer. + *

+ * This method always uses the unscaled version of the image + * to render the scaled rectangle and performs the required + * scaling on the fly. It does not use a cached, scaled version + * of the image for this operation. Scaling of the image from source + * to destination is performed such that the first coordinate + * of the source rectangle is mapped to the first coordinate of + * the destination rectangle, and the second source coordinate is + * mapped to the second destination coordinate. The subimage is + * scaled and flipped as needed to preserve those mappings. + * @param img the specified image to be drawn + * @param dx1 the x coordinate of the first corner of the + * destination rectangle. + * @param dy1 the y coordinate of the first corner of the + * destination rectangle. + * @param dx2 the x coordinate of the second corner of the + * destination rectangle. + * @param dy2 the y coordinate of the second corner of the + * destination rectangle. + * @param sx1 the x coordinate of the first corner of the + * source rectangle. + * @param sy1 the y coordinate of the first corner of the + * source rectangle. + * @param sx2 the x coordinate of the second corner of the + * source rectangle. + * @param sy2 the y coordinate of the second corner of the + * source rectangle. + * @param bgcolor the background color to paint under the + * non-opaque portions of the image. + * @param observer object to be notified as more of the image is + * scaled and converted. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + * @since JDK1.1 + */ + public boolean drawImage(Image img, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, + ImageObserver observer){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return false; + } + + /** + * Draws as much of the specified image as is currently available. + * The image is drawn with its top-left corner at + * (xy) in this graphics context's coordinate + * space. Transparent pixels in the image do not affect whatever + * pixels are already there. + *

+ * This method returns immediately in all cases, even if the + * complete image has not yet been loaded, and it has not been dithered + * and converted for the current output device. + *

+ * If the image has completely loaded and its pixels are + * no longer being changed, then + * drawImage returns true. + * Otherwise, drawImage returns false + * and as more of + * the image becomes available + * or it is time to draw another frame of animation, + * the process that loads the image notifies + * the specified image observer. + * @param img the specified image to be drawn. This method does + * nothing if img is null. + * @param x the x coordinate. + * @param y the y coordinate. + * @param observer object to be notified as more of + * the image is converted. + * @return false if the image pixels are still changing; + * true otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, + ImageObserver observer) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return false; + } + + /** + * Disposes of this graphics context and releases + * any system resources that it is using. + * A Graphics object cannot be used after + * disposehas been called. + *

+ * When a Java program runs, a large number of Graphics + * objects can be created within a short time frame. + * Although the finalization process of the garbage collector + * also disposes of the same system resources, it is preferable + * to manually free the associated resources by calling this + * method rather than to rely on a finalization process which + * may not run to completion for a long period of time. + *

+ * Graphics objects which are provided as arguments to the + * paint and update methods + * of components are automatically released by the system when + * those methods return. For efficiency, programmers should + * call dispose when finished using + * a Graphics object only if it was created + * directly from a component or another Graphics object. + * @see java.awt.Graphics#finalize + * @see java.awt.Component#paint + * @see java.awt.Component#update + * @see java.awt.Component#getGraphics + * @see java.awt.Graphics#create + */ + public void dispose() { + ; + } + + /** + * Draws a line, using the current color, between the points + * (x1, y1) and (x2, y2) + * in this graphics context's coordinate system. + * @param x1 the first point's x coordinate. + * @param y1 the first point's y coordinate. + * @param x2 the second point's x coordinate. + * @param y2 the second point's y coordinate. + */ + public void drawLine(int x1, int y1, int x2, int y2){ + Line2D line = new Line2D.Float(x1, y1, x2, y2); + draw(line); + } + + /** + * Fills a closed polygon defined by + * arrays of x and y coordinates. + *

+ * This method draws the polygon defined by nPoint line + * segments, where the first nPoint - 1 + * line segments are line segments from + * (xPoints[i - 1], yPoints[i - 1]) + * to (xPoints[i], yPoints[i]), for + * 1 ≤ i ≤ nPoints. + * The figure is automatically closed by drawing a line connecting + * the final point to the first point, if those points are different. + *

+ * The area inside the polygon is defined using an + * even-odd fill rule, also known as the alternating rule. + * @param xPoints a an array of x coordinates. + * @param yPoints a an array of y coordinates. + * @param nPoints a the total number of points. + * @see java.awt.Graphics#drawPolygon(int[], int[], int) + */ + public void fillPolygon(int[] xPoints, int[] yPoints, + int nPoints){ + java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints); + fill(polygon); + } + + /** + * Fills the specified rectangle. + * The left and right edges of the rectangle are at + * x and x + width - 1. + * The top and bottom edges are at + * y and y + height - 1. + * The resulting rectangle covers an area + * width pixels wide by + * height pixels tall. + * The rectangle is filled using the graphics context's current color. + * @param x the x coordinate + * of the rectangle to be filled. + * @param y the y coordinate + * of the rectangle to be filled. + * @param width the width of the rectangle to be filled. + * @param height the height of the rectangle to be filled. + * @see java.awt.Graphics#clearRect + * @see java.awt.Graphics#drawRect + */ + public void fillRect(int x, int y, int width, int height){ + Rectangle rect = new Rectangle(x, y, width, height); + fill(rect); + } + + /** + * Draws the outline of the specified rectangle. + * The left and right edges of the rectangle are at + * x and x + width. + * The top and bottom edges are at + * y and y + height. + * The rectangle is drawn using the graphics context's current color. + * @param x the x coordinate + * of the rectangle to be drawn. + * @param y the y coordinate + * of the rectangle to be drawn. + * @param width the width of the rectangle to be drawn. + * @param height the height of the rectangle to be drawn. + * @see java.awt.Graphics#fillRect + * @see java.awt.Graphics#clearRect + */ + public void drawRect(int x, int y, int width, int height) { + Rectangle rect = new Rectangle(x, y, width, height); + draw(rect); + } + + /** + * Draws a closed polygon defined by + * arrays of x and y coordinates. + * Each pair of (xy) coordinates defines a point. + *

+ * This method draws the polygon defined by nPoint line + * segments, where the first nPoint - 1 + * line segments are line segments from + * (xPoints[i - 1], yPoints[i - 1]) + * to (xPoints[i], yPoints[i]), for + * 1 ≤ i ≤ nPoints. + * The figure is automatically closed by drawing a line connecting + * the final point to the first point, if those points are different. + * @param xPoints a an array of x coordinates. + * @param yPoints a an array of y coordinates. + * @param nPoints a the total number of points. + * @see java.awt.Graphics#fillPolygon(int[],int[],int) + * @see java.awt.Graphics#drawPolyline + */ + public void drawPolygon(int[] xPoints, int[] yPoints, + int nPoints){ + java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints); + draw(polygon); + } + + /** + * Intersects the current clip with the specified rectangle. + * The resulting clipping area is the intersection of the current + * clipping area and the specified rectangle. If there is no + * current clipping area, either because the clip has never been + * set, or the clip has been cleared using setClip(null), + * the specified rectangle becomes the new clip. + * This method sets the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * This method can only be used to make the current clip smaller. + * To set the current clip larger, use any of the setClip methods. + * Rendering operations have no effect outside of the clipping area. + * @param x the x coordinate of the rectangle to intersect the clip with + * @param y the y coordinate of the rectangle to intersect the clip with + * @param width the width of the rectangle to intersect the clip with + * @param height the height of the rectangle to intersect the clip with + * @see #setClip(int, int, int, int) + * @see #setClip(Shape) + */ + public void clipRect(int x, int y, int width, int height){ + clip(new Rectangle(x, y, width, height)); + } + + /** + * Sets the current clipping area to an arbitrary clip shape. + * Not all objects that implement the Shape + * interface can be used to set the clip. The only + * Shape objects that are guaranteed to be + * supported are Shape objects that are + * obtained via the getClip method and via + * Rectangle objects. This method sets the + * user clip, which is independent of the clipping associated + * with device bounds and window visibility. + * @param clip the Shape to use to set the clip + * @see java.awt.Graphics#getClip() + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @since JDK1.1 + */ + public void setClip(Shape clip) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Returns the bounding rectangle of the current clipping area. + * This method refers to the user clip, which is independent of the + * clipping associated with device bounds and window visibility. + * If no clip has previously been set, or if the clip has been + * cleared using setClip(null), this method returns + * null. + * The coordinates in the rectangle are relative to the coordinate + * system origin of this graphics context. + * @return the bounding rectangle of the current clipping area, + * or null if no clip is set. + * @see java.awt.Graphics#getClip + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(int, int, int, int) + * @see java.awt.Graphics#setClip(Shape) + * @since JDK1.1 + */ + public Rectangle getClipBounds(){ + Shape c = getClip(); + if (c==null) { + return null; + } + return c.getBounds(); + } + + /** + * Draws the text given by the specified iterator, using this + * graphics context's current color. The iterator has to specify a font + * for each character. The baseline of the + * first character is at position (xy) in this + * graphics context's coordinate system. + * @param iterator the iterator whose text is to be drawn + * @param x the x coordinate. + * @param y the y coordinate. + * @see java.awt.Graphics#drawBytes + * @see java.awt.Graphics#drawChars + */ + public void drawString(AttributedCharacterIterator iterator, + int x, int y){ + drawString(iterator, (float)x, (float)y); + } + + /** + * Clears the specified rectangle by filling it with the background + * color of the current drawing surface. This operation does not + * use the current paint mode. + *

+ * Beginning with Java 1.1, the background color + * of offscreen images may be system dependent. Applications should + * use setColor followed by fillRect to + * ensure that an offscreen image is cleared to a specific color. + * @param x the x coordinate of the rectangle to clear. + * @param y the y coordinate of the rectangle to clear. + * @param width the width of the rectangle to clear. + * @param height the height of the rectangle to clear. + * @see java.awt.Graphics#fillRect(int, int, int, int) + * @see java.awt.Graphics#drawRect + * @see java.awt.Graphics#setColor(java.awt.Color) + * @see java.awt.Graphics#setPaintMode + * @see java.awt.Graphics#setXORMode(java.awt.Color) + */ + public void clearRect(int x, int y, int width, int height) { + Paint paint = getPaint(); + setColor(getBackground()); + fillRect(x, y, width, height); + setPaint(paint); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) { + ; + } + + /** + * Sets the current clip to the rectangle specified by the given + * coordinates. This method sets the user clip, which is + * independent of the clipping associated with device bounds + * and window visibility. + * Rendering operations have no effect outside of the clipping area. + * @param x the x coordinate of the new clip rectangle. + * @param y the y coordinate of the new clip rectangle. + * @param width the width of the new clip rectangle. + * @param height the height of the new clip rectangle. + * @see java.awt.Graphics#clipRect + * @see java.awt.Graphics#setClip(Shape) + * @since JDK1.1 + */ + public void setClip(int x, int y, int width, int height){ + setClip(new Rectangle(x, y, width, height)); + } + + /** + * Concatenates the current Graphics2D + * Transform with a rotation transform. + * Subsequent rendering is rotated by the specified radians relative + * to the previous origin. + * This is equivalent to calling transform(R), where R is an + * AffineTransform represented by the following matrix: + *

+     *          [   cos(theta)    -sin(theta)    0   ]
+     *          [   sin(theta)     cos(theta)    0   ]
+     *          [       0              0         1   ]
+     * 
+ * Rotating with a positive angle theta rotates points on the positive + * x axis toward the positive y axis. + * @param theta the angle of rotation in radians + */ + public void rotate(double theta){ + _transform.rotate(theta); + } + + /** + * Concatenates the current Graphics2D + * Transform with a translated rotation + * transform. Subsequent rendering is transformed by a transform + * which is constructed by translating to the specified location, + * rotating by the specified radians, and translating back by the same + * amount as the original translation. This is equivalent to the + * following sequence of calls: + *
+     *          translate(x, y);
+     *          rotate(theta);
+     *          translate(-x, -y);
+     * 
+ * Rotating with a positive angle theta rotates points on the positive + * x axis toward the positive y axis. + * @param theta the angle of rotation in radians + * @param x x coordinate of the origin of the rotation + * @param y y coordinate of the origin of the rotation + */ + public void rotate(double theta, double x, double y){ + _transform.rotate(theta, x, y); + } + + /** + * Concatenates the current Graphics2D + * Transform with a shearing transform. + * Subsequent renderings are sheared by the specified + * multiplier relative to the previous position. + * This is equivalent to calling transform(SH), where SH + * is an AffineTransform represented by the following + * matrix: + *
+     *          [   1   shx   0   ]
+     *          [  shy   1    0   ]
+     *          [   0    0    1   ]
+     * 
+ * @param shx the multiplier by which coordinates are shifted in + * the positive X axis direction as a function of their Y coordinate + * @param shy the multiplier by which coordinates are shifted in + * the positive Y axis direction as a function of their X coordinate + */ + public void shear(double shx, double shy){ + _transform.shear(shx, shy); + } + + /** + * Get the rendering context of the Font within this + * Graphics2D context. + * The {@link FontRenderContext} + * encapsulates application hints such as anti-aliasing and + * fractional metrics, as well as target device specific information + * such as dots-per-inch. This information should be provided by the + * application when using objects that perform typographical + * formatting, such as Font and + * TextLayout. This information should also be provided + * by applications that perform their own layout and need accurate + * measurements of various characteristics of glyphs such as advance + * and line height when various rendering hints have been applied to + * the text rendering. + * + * @return a reference to an instance of FontRenderContext. + * @see java.awt.font.FontRenderContext + * @see java.awt.Font#createGlyphVector(FontRenderContext,char[]) + * @see java.awt.font.TextLayout + * @since JDK1.2 + */ + public FontRenderContext getFontRenderContext() { + boolean isAntiAliased = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals( + getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING)); + boolean usesFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals( + getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS)); + + + return new FontRenderContext(new AffineTransform(), isAntiAliased, usesFractionalMetrics); + } + + /** + * Composes an AffineTransform object with the + * Transform in this Graphics2D according + * to the rule last-specified-first-applied. If the current + * Transform is Cx, the result of composition + * with Tx is a new Transform Cx'. Cx' becomes the + * current Transform for this Graphics2D. + * Transforming a point p by the updated Transform Cx' is + * equivalent to first transforming p by Tx and then transforming + * the result by the original Transform Cx. In other + * words, Cx'(p) = Cx(Tx(p)). A copy of the Tx is made, if necessary, + * so further modifications to Tx do not affect rendering. + * @param Tx the AffineTransform object to be composed with + * the current Transform + * @see #setTransform + * @see AffineTransform + */ + public void transform(AffineTransform Tx) { + _transform.concatenate(Tx); + } + + /** + * Renders a BufferedImage that is + * filtered with a + * {@link BufferedImageOp}. + * The rendering attributes applied include the Clip, + * Transform + * and Composite attributes. This is equivalent to: + *
+     * img1 = op.filter(img, null);
+     * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);
+     * 
+ * @param img the BufferedImage to be rendered + * @param op the filter to be applied to the image before rendering + * @param x the x coordinate in user space where the image is rendered + * @param y the y coordinate in user space where the image is rendered + * @see #_transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip(Shape) + */ + public void drawImage(BufferedImage img, + BufferedImageOp op, + int x, + int y){ + img = op.filter(img, null); + drawImage(img, x, y, null); + } + + /** + * Sets the background color for the Graphics2D context. + * The background color is used for clearing a region. + * When a Graphics2D is constructed for a + * Component, the background color is + * inherited from the Component. Setting the background color + * in the Graphics2D context only affects the subsequent + * clearRect calls and not the background color of the + * Component. To change the background + * of the Component, use appropriate methods of + * the Component. + * @param color the background color that isused in + * subsequent calls to clearRect + * @see #getBackground + * @see java.awt.Graphics#clearRect + */ + public void setBackground(Color color) { + if(color == null) + return; + + _background = color; + } + + /** + * Returns the background color used for clearing a region. + * @return the current Graphics2D Color, + * which defines the background color. + * @see #setBackground + */ + public Color getBackground(){ + return _background; + } + + /** + * Sets the Composite for the Graphics2D context. + * The Composite is used in all drawing methods such as + * drawImage, drawString, draw, + * and fill. It specifies how new pixels are to be combined + * with the existing pixels on the graphics device during the rendering + * process. + *

If this Graphics2D context is drawing to a + * Component on the display screen and the + * Composite is a custom object rather than an + * instance of the AlphaComposite class, and if + * there is a security manager, its checkPermission + * method is called with an AWTPermission("readDisplayPixels") + * permission. + * + * @param comp the Composite object to be used for rendering + * @throws SecurityException + * if a custom Composite object is being + * used to render to the screen and a security manager + * is set and its checkPermission method + * does not allow the operation. + * @see java.awt.Graphics#setXORMode + * @see java.awt.Graphics#setPaintMode + * @see java.awt.AlphaComposite + */ + public void setComposite(Composite comp){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Returns the current Composite in the + * Graphics2D context. + * @return the current Graphics2D Composite, + * which defines a compositing style. + * @see #setComposite + */ + public Composite getComposite(){ + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return null; + } + + /** + * Returns the value of a single preference for the rendering algorithms. + * Hint categories include controls for rendering quality and overall + * time/quality trade-off in the rendering process. Refer to the + * RenderingHints class for definitions of some common + * keys and values. + * @param hintKey the key corresponding to the hint to get. + * @return an object representing the value for the specified hint key. + * Some of the keys and their associated values are defined in the + * RenderingHints class. + * @see RenderingHints + */ + public Object getRenderingHint(RenderingHints.Key hintKey){ + return _hints.get(hintKey); + } + + /** + * Sets the value of a single preference for the rendering algorithms. + * Hint categories include controls for rendering quality and overall + * time/quality trade-off in the rendering process. Refer to the + * RenderingHints class for definitions of some common + * keys and values. + * @param hintKey the key of the hint to be set. + * @param hintValue the value indicating preferences for the specified + * hint category. + * @see RenderingHints + */ + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue){ + _hints.put(hintKey, hintValue); + } + + + /** + * Renders the text of the specified + * {@link GlyphVector} using + * the Graphics2D context's rendering attributes. + * The rendering attributes applied include the Clip, + * Transform, Paint, and + * Composite attributes. The GlyphVector + * specifies individual glyphs from a {@link Font}. + * The GlyphVector can also contain the glyph positions. + * This is the fastest way to render a set of characters to the + * screen. + * + * @param g the GlyphVector to be rendered + * @param x the x position in user space where the glyphs should be + * rendered + * @param y the y position in user space where the glyphs should be + * rendered + * + * @see java.awt.Font#createGlyphVector(FontRenderContext, char[]) + * @see java.awt.font.GlyphVector + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #setTransform + * @see #setComposite + * @see #setClip(Shape) + */ + public void drawGlyphVector(GlyphVector g, float x, float y) { + Shape glyphOutline = g.getOutline(x, y); + fill(glyphOutline); + } + + /** + * Returns the device configuration associated with this + * Graphics2D. + * @return the device configuration + */ + public GraphicsConfiguration getDeviceConfiguration() { + return GraphicsEnvironment.getLocalGraphicsEnvironment(). + getDefaultScreenDevice().getDefaultConfiguration(); + } + + /** + * Sets the values of an arbitrary number of preferences for the + * rendering algorithms. + * Only values for the rendering hints that are present in the + * specified Map object are modified. + * All other preferences not present in the specified + * object are left unmodified. + * Hint categories include controls for rendering quality and + * overall time/quality trade-off in the rendering process. + * Refer to the RenderingHints class for definitions of + * some common keys and values. + * @param hints the rendering hints to be set + * @see RenderingHints + */ + public void addRenderingHints(Map hints){ + this._hints.putAll(hints); + } + + /** + * Concatenates the current + * Graphics2D Transform + * with a translation transform. + * Subsequent rendering is translated by the specified + * distance relative to the previous position. + * This is equivalent to calling transform(T), where T is an + * AffineTransform represented by the following matrix: + *

+     *          [   1    0    tx  ]
+     *          [   0    1    ty  ]
+     *          [   0    0    1   ]
+     * 
+ * @param tx the distance to translate along the x-axis + * @param ty the distance to translate along the y-axis + */ + public void translate(double tx, double ty){ + _transform.translate(tx, ty); + } + + /** + * Renders the text of the specified iterator, using the + * Graphics2D context's current Paint. The + * iterator must specify a font + * for each character. The baseline of the + * first character is at position (xy) in the + * User Space. + * The rendering attributes applied include the Clip, + * Transform, Paint, and + * Composite attributes. + * For characters in script systems such as Hebrew and Arabic, + * the glyphs can be rendered from right to left, in which case the + * coordinate supplied is the location of the leftmost character + * on the baseline. + * @param iterator the iterator whose text is to be rendered + * @param x the x coordinate where the iterator's text is to be + * rendered + * @param y the y coordinate where the iterator's text is to be + * rendered + * @see #setPaint + * @see java.awt.Graphics#setColor + * @see #setTransform + * @see #setComposite + * @see #setClip + */ + public void drawString(AttributedCharacterIterator iterator, float x, float y) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Checks whether or not the specified Shape intersects + * the specified {@link Rectangle}, which is in device + * space. If onStroke is false, this method checks + * whether or not the interior of the specified Shape + * intersects the specified Rectangle. If + * onStroke is true, this method checks + * whether or not the Stroke of the specified + * Shape outline intersects the specified + * Rectangle. + * The rendering attributes taken into account include the + * Clip, Transform, and Stroke + * attributes. + * @param rect the area in device space to check for a hit + * @param s the Shape to check for a hit + * @param onStroke flag used to choose between testing the + * stroked or the filled shape. If the flag is true, the + * Stroke oultine is tested. If the flag is + * false, the filled Shape is tested. + * @return true if there is a hit; false + * otherwise. + * @see #setStroke + * @see #fill(Shape) + * @see #draw(Shape) + * @see #_transform + * @see #setTransform + * @see #clip + * @see #setClip(Shape) + */ + public boolean hit(Rectangle rect, + Shape s, + boolean onStroke){ + if (onStroke) { + s = getStroke().createStrokedShape(s); + } + + s = getTransform().createTransformedShape(s); + + return s.intersects(rect); + } + + /** + * Gets the preferences for the rendering algorithms. Hint categories + * include controls for rendering quality and overall time/quality + * trade-off in the rendering process. + * Returns all of the hint key/value pairs that were ever specified in + * one operation. Refer to the + * RenderingHints class for definitions of some common + * keys and values. + * @return a reference to an instance of RenderingHints + * that contains the current preferences. + * @see RenderingHints + */ + public RenderingHints getRenderingHints(){ + return _hints; + } + + /** + * Replaces the values of all preferences for the rendering + * algorithms with the specified hints. + * The existing values for all rendering hints are discarded and + * the new set of known hints and values are initialized from the + * specified {@link Map} object. + * Hint categories include controls for rendering quality and + * overall time/quality trade-off in the rendering process. + * Refer to the RenderingHints class for definitions of + * some common keys and values. + * @param hints the rendering hints to be set + * @see RenderingHints + */ + public void setRenderingHints(Map hints){ + this._hints = new RenderingHints(null); + this._hints.putAll(hints); + } + + /** + * Renders an image, applying a transform from image space into user space + * before drawing. + * The transformation from user space into device space is done with + * the current Transform in the Graphics2D. + * The specified transformation is applied to the image before the + * transform attribute in the Graphics2D context is applied. + * The rendering attributes applied include the Clip, + * Transform, and Composite attributes. + * Note that no rendering is done if the specified transform is + * noninvertible. + * @param img the Image to be rendered + * @param xform the transformation from image space into user space + * @param obs the {@link ImageObserver} + * to be notified as more of the Image + * is converted + * @return true if the Image is + * fully loaded and completely rendered; + * false if the Image is still being loaded. + * @see #_transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip(Shape) + */ + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return false; + } + + /** + * Draws as much of the specified image as has already been scaled + * to fit inside the specified rectangle. + *

+ * The image is drawn inside the specified rectangle of this + * graphics context's coordinate space, and is scaled if + * necessary. Transparent pixels do not affect whatever pixels + * are already there. + *

+ * This method returns immediately in all cases, even if the + * entire image has not yet been scaled, dithered, and converted + * for the current output device. + * If the current output representation is not yet complete, then + * drawImage returns false. As more of + * the image becomes available, the process that loads the image notifies + * the image observer by calling its imageUpdate method. + *

+ * A scaled version of an image will not necessarily be + * available immediately just because an unscaled version of the + * image has been constructed for this output device. Each size of + * the image may be cached separately and generated from the original + * data in a separate image production sequence. + * @param img the specified image to be drawn. This method does + * nothing if img is null. + * @param x the x coordinate. + * @param y the y coordinate. + * @param width the width of the rectangle. + * @param height the height of the rectangle. + * @param observer object to be notified as more of + * the image is converted. + * @return false if the image pixels are still changing; + * true otherwise. + * @see java.awt.Image + * @see java.awt.image.ImageObserver + * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) + */ + public boolean drawImage(Image img, int x, int y, + int width, int height, + ImageObserver observer) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + return false; + } + + /** + * Creates a new Graphics object that is + * a copy of this Graphics object. + * @return a new graphics context that is a copy of + * this graphics context. + */ + public Graphics create() { + try { + return (Graphics)clone(); + } catch (CloneNotSupportedException e){ + throw new RuntimeException(e); + } + } + + /** + * Gets the font metrics for the specified font. + * @return the font metrics for the specified font. + * @param f the specified font + * @see java.awt.Graphics#getFont + * @see java.awt.FontMetrics + * @see java.awt.Graphics#getFontMetrics() + */ + @SuppressWarnings("deprecation") + @SuppressForbidden + public FontMetrics getFontMetrics(Font f) { + return Toolkit.getDefaultToolkit().getFontMetrics(f); + } + + /** + * Sets the paint mode of this graphics context to alternate between + * this graphics context's current color and the new specified color. + * This specifies that logical pixel operations are performed in the + * XOR mode, which alternates pixels between the current color and + * a specified XOR color. + *

+ * When drawing operations are performed, pixels which are the + * current color are changed to the specified color, and vice versa. + *

+ * Pixels that are of colors other than those two colors are changed + * in an unpredictable but reversible manner; if the same figure is + * drawn twice, then all pixels are restored to their original values. + * @param c1 the XOR alternation color + */ + public void setXORMode(Color c1) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Sets the paint mode of this graphics context to overwrite the + * destination with this graphics context's current color. + * This sets the logical pixel operation function to the paint or + * overwrite mode. All subsequent rendering operations will + * overwrite the destination with the current color. + */ + public void setPaintMode() { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Renders a + * {@link RenderableImage}, + * applying a transform from image space into user space before drawing. + * The transformation from user space into device space is done with + * the current Transform in the Graphics2D. + * The specified transformation is applied to the image before the + * transform attribute in the Graphics2D context is applied. + * The rendering attributes applied include the Clip, + * Transform, and Composite attributes. Note + * that no rendering is done if the specified transform is + * noninvertible. + *

+ * Rendering hints set on the Graphics2D object might + * be used in rendering the RenderableImage. + * If explicit control is required over specific hints recognized by a + * specific RenderableImage, or if knowledge of which hints + * are used is required, then a RenderedImage should be + * obtained directly from the RenderableImage + * and rendered using + *{@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}. + * @param img the image to be rendered. This method does + * nothing if img is null. + * @param xform the transformation from image space into user space + * @see #_transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + * @see #drawRenderedImage + */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + /** + * Renders a {@link RenderedImage}, + * applying a transform from image + * space into user space before drawing. + * The transformation from user space into device space is done with + * the current Transform in the Graphics2D. + * The specified transformation is applied to the image before the + * transform attribute in the Graphics2D context is applied. + * The rendering attributes applied include the Clip, + * Transform, and Composite attributes. Note + * that no rendering is done if the specified transform is + * noninvertible. + * @param img the image to be rendered. This method does + * nothing if img is null. + * @param xform the transformation from image space into user space + * @see #_transform + * @see #setTransform + * @see #setComposite + * @see #clip + * @see #setClip + */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) { + if (log.check(POILogger.WARN)) { + log.log(POILogger.WARN, "Not implemented"); + } + } + + protected void applyStroke(SimpleShape shape) { + if (_stroke instanceof BasicStroke){ + BasicStroke bs = (BasicStroke)_stroke; + shape.setStrokeStyle((double)bs.getLineWidth()); + float[] dash = bs.getDashArray(); + if (dash != null) { + //TODO: implement more dashing styles + shape.setStrokeStyle(StrokeStyle.LineDash.DASH); + } + } + } + + protected void applyPaint(SimpleShape shape) { + if (_paint instanceof Color) { + shape.setFillColor((Color)_paint); + } + } +} diff --git a/src/java/org/apache/poi/sl/usermodel/SimpleShape.java b/src/java/org/apache/poi/sl/usermodel/SimpleShape.java index ceed729e09..8ed151b496 100644 --- a/src/java/org/apache/poi/sl/usermodel/SimpleShape.java +++ b/src/java/org/apache/poi/sl/usermodel/SimpleShape.java @@ -17,6 +17,8 @@ package org.apache.poi.sl.usermodel; +import java.awt.Color; + import org.apache.poi.sl.draw.geom.CustomGeometry; import org.apache.poi.sl.draw.geom.IAdjustableShape; @@ -25,15 +27,66 @@ public interface SimpleShape< S extends Shape, P extends TextParagraph > extends Shape, IAdjustableShape, PlaceableShape { + + enum Placeholder { + TITLE, + BODY, + CENTERED_TITLE, + SUBTITLE, + DATETIME, + SLIDE_NUMBER, + FOOTER, + HEADER, + CONTENT, + CHART, + TABLE, + CLIP_ART, + DGM, + MEDIA, + SLIDE_IMAGE, + PICTURE + } + FillStyle getFillStyle(); + LineDecoration getLineDecoration(); + StrokeStyle getStrokeStyle(); + + /** + * Sets the line attributes. + * Possible attributes are Double (width), LineCap, LineDash, LineCompound, Color + * (implementations of PaintStyle aren't yet supported ...) + * + * If no styles are given, the line will be hidden + * + * @param styles the line attributes + */ + void setStrokeStyle(Object... styles); CustomGeometry getGeometry(); - + ShapeType getShapeType(); + void setShapeType(ShapeType type); boolean isPlaceholder(); - + Shadow getShadow(); + + /** + * Returns the solid color fill. + * + * @return solid fill color of null if not set or fill color + * is not solid (pattern or gradient) + */ + Color getFillColor(); + + /** + * Specifies a solid color fill. The shape is filled entirely with the + * specified color. + * + * @param color the solid color fill. The value of null unsets + * the solid fill attribute from the underlying implementation + */ + void setFillColor(Color color); } diff --git a/src/java/org/apache/poi/sl/usermodel/SlideShow.java b/src/java/org/apache/poi/sl/usermodel/SlideShow.java index 53449e76d5..968911b95f 100644 --- a/src/java/org/apache/poi/sl/usermodel/SlideShow.java +++ b/src/java/org/apache/poi/sl/usermodel/SlideShow.java @@ -48,6 +48,13 @@ public interface SlideShow< * @return the page size */ Dimension getPageSize(); + + /** + * Change the current page size + * + * @param pgsize page size (in points) + */ + void setPageSize(Dimension pgsize); /** * Returns all Pictures of this slideshow. diff --git a/src/java/org/apache/poi/sl/usermodel/StrokeStyle.java b/src/java/org/apache/poi/sl/usermodel/StrokeStyle.java index 244173fed4..be93a994de 100644 --- a/src/java/org/apache/poi/sl/usermodel/StrokeStyle.java +++ b/src/java/org/apache/poi/sl/usermodel/StrokeStyle.java @@ -20,18 +20,27 @@ package org.apache.poi.sl.usermodel; public interface StrokeStyle { enum LineCap { /** Rounded ends */ - ROUND(1), + ROUND(0,1), /** Square protrudes by half line width */ - SQUARE(2), + SQUARE(1,2), /** Line ends at end point*/ - FLAT(3); + FLAT(2,3); + public final int nativeId; public final int ooxmlId; - LineCap(int ooxmlId) { + LineCap(int nativeId, int ooxmlId) { + this.nativeId = nativeId; this.ooxmlId = ooxmlId; } + public static LineCap fromNativeId(int nativeId) { + for (LineCap ld : values()) { + if (ld.nativeId == nativeId) return ld; + } + return null; + } + public static LineCap fromOoxmlId(int ooxmlId) { for (LineCap lc : values()) { if (lc.ooxmlId == ooxmlId) return lc; @@ -96,20 +105,22 @@ public interface StrokeStyle { enum LineCompound { /** Single line (of width lineWidth) - native 0 / ooxml default */ - SINGLE(0), + SINGLE(0, 1), /** Double lines of equal width - native 1 / ooxml "dbl" */ - DOUBLE(1), + DOUBLE(1, 2), /** Double lines, one thick, one thin - native 2 / ooxml "thickThin" */ - THICK_THIN(2), + THICK_THIN(2, 3), /** Double lines, reverse order - native 3 / ooxml "thinThick" */ - THIN_THICK(3), + THIN_THICK(3, 4), /** Three lines, thin, thick, thin - native 4 / ooxml "tri" */ - TRIPLE(4); + TRIPLE(4, 5); public final int nativeId; + public final int ooxmlId; - LineCompound(int nativeId) { + LineCompound(int nativeId, int ooxmlId) { this.nativeId = nativeId; + this.ooxmlId = ooxmlId; } public static LineCompound fromNativeId(int nativeId) { @@ -118,6 +129,13 @@ public interface StrokeStyle { } return null; } + + public static LineCompound fromOoxmlId(int ooxmlId) { + for (LineCompound lc : values()) { + if (lc.ooxmlId == ooxmlId) return lc; + } + return null; + } } diff --git a/src/java/org/apache/poi/sl/usermodel/TableCell.java b/src/java/org/apache/poi/sl/usermodel/TableCell.java index 278573bab5..5ad4c4c296 100644 --- a/src/java/org/apache/poi/sl/usermodel/TableCell.java +++ b/src/java/org/apache/poi/sl/usermodel/TableCell.java @@ -17,9 +17,70 @@ package org.apache.poi.sl.usermodel; +import java.awt.Color; + +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; + public interface TableCell< S extends Shape, P extends TextParagraph > extends TextShape { + enum BorderEdge { bottom, left, top, right }; + + /** + * Return line style of given edge or {@code null} if border is not defined + * + * @param edge the border edge + * @return line style of given edge or {@code null} if border is not defined + */ + StrokeStyle getBorderStyle(BorderEdge edge); + + /** + * Sets the {@link StrokeStyle} of the given border edge. + * A {@code null} property of the style is ignored. + * + * @param edge border edge + * @param style the new stroke style + */ + void setBorderStyle(BorderEdge edge, StrokeStyle style); + + /** + * Convenience method for setting the border width. + * + * @param edge border edge + * @param width the new border width + */ + void setBorderWidth(BorderEdge edge, double width); + + /** + * Convenience method for setting the border color. + * + * @param edge border edge + * @param color the new border color + */ + void setBorderColor(BorderEdge edge, Color color); + + /** + * Convenience method for setting the border line compound. + * + * @param edge border edge + * @param compound the new border line compound + */ + void setBorderCompound(BorderEdge edge, LineCompound compound); + /** + * Convenience method for setting the border line dash. + * + * @param edge border edge + * @param dash the new border line dash + */ + void setBorderDash(BorderEdge edge, LineDash dash); + + /** + * Remove all line attributes of the given border edge + * + * @param edge the border edge to be cleared + */ + void removeBorder(BorderEdge edge); } diff --git a/src/java/org/apache/poi/sl/usermodel/TableShape.java b/src/java/org/apache/poi/sl/usermodel/TableShape.java index 29342e7d94..5614484467 100644 --- a/src/java/org/apache/poi/sl/usermodel/TableShape.java +++ b/src/java/org/apache/poi/sl/usermodel/TableShape.java @@ -21,5 +21,25 @@ public interface TableShape< S extends Shape, P extends TextParagraph > extends Shape, PlaceableShape { - // to be defined ... + int getNumberOfColumns(); + + int getNumberOfRows(); + + TableCell getCell(int row, int col); + + /** + * Sets the width (in points) of the n-th column + * + * @param idx the column index (0-based) + * @param width the width (in points) + */ + void setColumnWidth(int idx, double width); + + /** + * Sets the row height. + * + * @param row the row index (0-based) + * @param height the height to set (in points) + */ + void setRowHeight(int row, double height); } diff --git a/src/java/org/apache/poi/sl/usermodel/TextBox.java b/src/java/org/apache/poi/sl/usermodel/TextBox.java index 8fa997c89e..bc6951103a 100644 --- a/src/java/org/apache/poi/sl/usermodel/TextBox.java +++ b/src/java/org/apache/poi/sl/usermodel/TextBox.java @@ -17,6 +17,13 @@ package org.apache.poi.sl.usermodel; +/** + * Represents a TextFrame shape in PowerPoint. + *

+ * Contains the text in a text frame as well as the properties and methods + * that control alignment and anchoring of the text. + *

+ */ public interface TextBox< S extends Shape, P extends TextParagraph diff --git a/src/java/org/apache/poi/sl/usermodel/TextParagraph.java b/src/java/org/apache/poi/sl/usermodel/TextParagraph.java index 00a016058d..b35d323e1a 100644 --- a/src/java/org/apache/poi/sl/usermodel/TextParagraph.java +++ b/src/java/org/apache/poi/sl/usermodel/TextParagraph.java @@ -18,6 +18,7 @@ package org.apache.poi.sl.usermodel; import java.awt.Color; +import java.util.List; @@ -339,4 +340,9 @@ public interface TextParagraph< TextShape getParentShape(); + + /** + * Fetch the text runs that are contained within this block of text + */ + List getTextRuns(); } diff --git a/src/java/org/apache/poi/sl/usermodel/TextRun.java b/src/java/org/apache/poi/sl/usermodel/TextRun.java index bd0164c275..9eb27b616e 100644 --- a/src/java/org/apache/poi/sl/usermodel/TextRun.java +++ b/src/java/org/apache/poi/sl/usermodel/TextRun.java @@ -30,23 +30,23 @@ public interface TextRun { SMALL, ALL } - + String getRawText(); - void setText(String text); - - TextCap getTextCap(); - - /** - * Returns the font color. - * This usually returns a {@link SolidPaint}, but but also other classes are possible - * - * @return the font color/paint - * + void setText(String text); + + TextCap getTextCap(); + + /** + * Returns the font color. + * This usually returns a {@link SolidPaint}, but but also other classes are possible + * + * @return the font color/paint + * * @see org.apache.poi.sl.draw.DrawPaint#getPaint(java.awt.Graphics2D, PaintStyle) * @see SolidPaint#getSolidColor() - * @see org.apache.poi.sl.draw.DrawPaint#applyColorTransform(ColorStyle) - */ - PaintStyle getFontColor(); + * @see org.apache.poi.sl.draw.DrawPaint#applyColorTransform(ColorStyle) + */ + PaintStyle getFontColor(); /** * Sets the (solid) font color - convenience function @@ -56,41 +56,104 @@ public interface TextRun { void setFontColor(Color color); /** - * Sets the font color - * - * @param color the color - * - * @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color) - */ - void setFontColor(PaintStyle color); - - + * Sets the font color + * + * @param color the color + * + * @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color) + */ + void setFontColor(PaintStyle color); + + /** * Returns the font size which is either set directly on this text run or * given from the slide layout - * + * * @return font size in points or null if font size is not set. */ - Double getFontSize(); + Double getFontSize(); /** * Sets the font size directly on this text run, if null is given, the * font size defaults to the values given from the slide layout - * + * * @param fontSize font size in points, if null the underlying fontsize will be unset */ - void setFontSize(Double fontSize); - String getFontFamily(); - - boolean isBold(); - boolean isItalic(); - boolean isUnderlined(); - boolean isStrikethrough(); - boolean isSubscript(); - boolean isSuperscript(); - - /** - * @return the pitch and family id or -1 if not applicable - */ - byte getPitchAndFamily(); + void setFontSize(Double fontSize); + + /** + * @return font family or null if not set + */ + String getFontFamily(); + + /** + * Specifies the typeface, or name of the font that is to be used for this text run. + * + * @param typeface the font to apply to this text run. + * The value of null unsets the Typeface attrubute from the underlying xml. + */ + void setFontFamily(String typeface); + + /** + * @return true, if text is bold + */ + boolean isBold(); + + /** + * Sets the bold state + * + * @param bold set to true for bold text, false for normal weight + */ + void setBold(boolean bold); + + /** + * @return true, if text is italic + */ + boolean isItalic(); + + /** + * Sets the italic state + * + * @param italic set to true for italic text, false for non-italics + */ + void setItalic(boolean italic); + + /** + * @return true, if text is underlined + */ + boolean isUnderlined(); + + /** + * Sets the underlined state + * + * @param underlined set to true for underlined text, false for no underlining + */ + void setUnderlined(boolean underlined); + + /** + * @return true, if text is stroked + */ + boolean isStrikethrough(); + + /** + * Sets the strikethrough state + * + * @param stroked set to true for stroked text, false for no stroking + */ + void setStrikethrough(boolean stroked); + + /** + * @return true, if text is sub scripted + */ + boolean isSubscript(); + + /** + * @return true, if text is super scripted + */ + boolean isSuperscript(); + + /** + * @return the pitch and family id or -1 if not applicable + */ + byte getPitchAndFamily(); } diff --git a/src/java/org/apache/poi/sl/usermodel/TextShape.java b/src/java/org/apache/poi/sl/usermodel/TextShape.java index f487c108a4..0ec2ddfb91 100644 --- a/src/java/org/apache/poi/sl/usermodel/TextShape.java +++ b/src/java/org/apache/poi/sl/usermodel/TextShape.java @@ -26,7 +26,7 @@ public interface TextShape< /** * Vertical Text Types */ - public enum TextDirection { + enum TextDirection { /** * Horizontal text. This should be default. */ @@ -59,7 +59,7 @@ public interface TextShape< * Auto-fitting is when text within a shape is scaled in order to contain all the text inside *

*/ - public enum TextAutofit { + enum TextAutofit { /** * Specifies that text within the text body should not be auto-fit to the bounding box. * Auto-fitting is when text within a text box is scaled in order to remain inside @@ -89,6 +89,46 @@ public interface TextShape< */ SHAPE } + + /** + * This enum represents a compromise for the handling of + * HSLF run types (see org.apache.poi.hslf.record.TextHeaderAtom) and + * XSLF placeholders (see org.apache.poi.xslf.usermodel.Placeholder). + * When a shape is considered a placeholder by the generating application + * it can have special properties to alert the user that they may enter content into the shape. + * + * This enum and the handling around it may change significantly in future releases + */ + enum TextPlaceholder { + /** Title placeholder shape text */ + TITLE, + /** Body placeholder shape text */ + BODY, + /** Center title placeholder shape text */ + CENTER_TITLE, + /** Center body placeholder shape text */ + CENTER_BODY, + /** Half-sized body placeholder shape text */ + HALF_BODY, + /** Quarter-sized body placeholder shape text */ + QUARTER_BODY, + /** Notes placeholder shape text */ + NOTES, + /** Any other text */ + OTHER + } + + /** + * Sets (overwrites) the current text. + * Uses the properties of the first paragraph / textrun. + * Text paragraphs are split by \\r or \\n. + * New lines within text run are split by \\u000b + * + * @param text the text string used by this object. + * + * @return the last text run of the - potential split - text + */ + TextRun setText(String text); /** * @return the TextParagraphs for this text box @@ -99,6 +139,13 @@ public interface TextShape< * @return text shape margin */ Insets2D getInsets(); + + /** + * Sets the shape margins + * + * @param insets the new shape margins + */ + void setInsets(Insets2D insets); /** * Compute the cumulative height occupied by the text @@ -112,6 +159,14 @@ public interface TextShape< */ VerticalAlignment getVerticalAlignment(); + /** + * Sets the type of vertical alignment for the text. + * + * @param vAlign - the type of alignment. + * A {@code null} values unsets this property. + */ + void setVerticalAlignment(VerticalAlignment vAlign); + /** * Returns if the text is centered. * If true and if the individual paragraph settings allow it, @@ -122,13 +177,36 @@ public interface TextShape< */ boolean isHorizontalCentered(); + /** + * Sets if the paragraphs are horizontal centered + * + * @param isCentered true, if the paragraphs are horizontal centered + * A {@code null} values unsets this property. + */ + void setHorizontalCentered(Boolean isCentered); + /** * @return whether to wrap words within the bounding rectangle */ boolean getWordWrap(); + /** + * @param wrap whether to wrap words within the bounding rectangle + */ + void setWordWrap(boolean wrap); + /** * @return vertical orientation of the text */ TextDirection getTextDirection(); + + /** + * Sets the text placeholder + */ + void setTextPlaceholder(TextPlaceholder placeholder); + + /** + * @return the text placeholder + */ + TextPlaceholder getTextPlaceholder(); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java deleted file mode 100644 index 087b28c054..0000000000 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - */ -package org.apache.poi.xslf.usermodel; - -/** - * @author Yegor Kozlov - */ -public enum Placeholder { - TITLE, - BODY, - CENTERED_TITLE, - SUBTITLE, - DATETIME, - SLIDE_NUMBER, - FOOTER, - HEADER, - CONTENT, - CHART, - TABLE, - CLIP_ART, - DGM, - MEDIA, - SLIDE_IMAGE, - PICTURE -} diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java index e896420e93..bd150811a2 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java @@ -41,7 +41,6 @@ import org.apache.poi.sl.usermodel.PictureData.PictureType; import org.apache.poi.sl.usermodel.Resources; import org.apache.poi.sl.usermodel.SlideShow; import org.apache.poi.util.Beta; -import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.IOUtils; import org.apache.poi.util.Internal; import org.apache.poi.util.LittleEndian; @@ -404,11 +403,7 @@ implements SlideShow { return slide; } - /** - * Returns the current page size - * - * @return the page size - */ + @Override public Dimension getPageSize(){ CTSlideSize sz = _presentation.getSldSz(); int cx = sz.getCx(); @@ -416,11 +411,7 @@ implements SlideShow { return new Dimension((int)Units.toPoints(cx), (int)Units.toPoints(cy)); } - /** - * Sets the page size to the given Dimension object. - * - * @param pgSize page size - */ + @Override public void setPageSize(Dimension pgSize){ CTSlideSize sz = CTSlideSize.Factory.newInstance(); sz.setCx(Units.toEMU(pgSize.getWidth())); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java index b9e4004488..e45df5ee29 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java @@ -25,7 +25,12 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D; import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType; +import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType; +import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual; @@ -71,14 +76,26 @@ public class XSLFAutoShape extends XSLFTextShape prst.addNewAvLst(); return ct; } + + protected static void initTextBody(CTTextBody txBody) { + CTTextBodyProperties bodypr = txBody.addNewBodyPr(); + bodypr.setAnchor(STTextAnchoringType.T); + bodypr.setRtlCol(false); + CTTextParagraph p = txBody.addNewP(); + p.addNewPPr().setAlgn(STTextAlignType.L); + CTTextCharacterProperties endPr = p.addNewEndParaRPr(); + endPr.setLang("en-US"); + endPr.setSz(1100); + p.addNewR().setT(""); + txBody.addNewLstStyle(); + } protected CTTextBody getTextBody(boolean create){ CTShape shape = (CTShape)getXmlObject(); CTTextBody txBody = shape.getTxBody(); if (txBody == null && create) { txBody = shape.addNewTxBody(); - txBody.addNewBodyPr(); - txBody.addNewLstStyle(); + initTextBody(txBody); } return txBody; } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java index 37dbc33a22..dc1ef5af2c 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java @@ -33,6 +33,7 @@ import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; import org.apache.poi.sl.usermodel.PlaceableShape; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Shape; import org.apache.poi.util.Beta; import org.apache.poi.util.Internal; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java index f5d0207b78..daca97131d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java @@ -39,6 +39,7 @@ import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawPictureShape; import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.usermodel.PictureData; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Sheet; import org.apache.poi.util.Beta; import org.apache.poi.util.IOUtils; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java index 821cb07dff..28c98889cb 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java @@ -88,25 +88,23 @@ public abstract class XSLFSimpleShape extends XSLFShape super(shape,sheet); } - /** - * - * @param type - */ - public void setShapeType(ShapeType type){ + @Override + public void setShapeType(ShapeType type) { STShapeType.Enum geom = STShapeType.Enum.forInt(type.ooxmlId); getSpPr().getPrstGeom().setPrst(geom); } + @Override public ShapeType getShapeType(){ STShapeType.Enum geom = getSpPr().getPrstGeom().getPrst(); return ShapeType.forId(geom.intValue(), true); } - + protected CTTransform2D getSafeXfrm() { CTTransform2D xfrm = getXfrm(); return (xfrm == null ? getSpPr().addNewXfrm() : xfrm); } - + protected CTTransform2D getXfrm() { PropertyFetcher fetcher = new PropertyFetcher() { public boolean fetch(XSLFShape shape) { @@ -151,7 +149,7 @@ public abstract class XSLFSimpleShape extends XSLFShape ext.setCx(cx); ext.setCy(cy); } - + @Override public void setRotation(double theta) { getSafeXfrm().setRot((int) (theta * 60000)); @@ -185,7 +183,7 @@ public abstract class XSLFSimpleShape extends XSLFShape return (xfrm == null || !xfrm.isSetFlipV()) ? false : getXfrm().getFlipV(); } - + /** * Get default line properties defined in the theme (if any). * Used internally to resolve shape properties. @@ -199,7 +197,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (lnRef == null) return null; // 1-based index of a line style within the style matrix int idx = (int)lnRef.getIdx(); - + XSLFTheme theme = getSheet().getTheme(); if (theme == null) return null; CTBaseStyles styles = theme.getXmlObject().getThemeElements(); @@ -208,7 +206,7 @@ public abstract class XSLFSimpleShape extends XSLFShape if (styleMatrix == null) return null; CTLineStyleList lineStyles = styleMatrix.getLnStyleLst(); if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) return null; - + return lineStyles.getLnArray(idx - 1); } @@ -262,7 +260,7 @@ public abstract class XSLFSimpleShape extends XSLFShape setValue(null); // use it as 'nofill' value return true; } - + PaintStyle paint = null; PackagePart pp = getSheet().getPackagePart(); for (XmlObject obj : spPr.selectPath("*")) { @@ -290,11 +288,11 @@ public abstract class XSLFSimpleShape extends XSLFShape PaintStyle paint = fetcher.getValue(); if (paint != null) return paint; - + // line color was not found, check if it is defined in the theme CTShapeStyle style = getSpStyle(); if (style == null) return null; - + // get a reference to a line style within the style matrix. CTStyleMatrixReference lnRef = style.getLnRef(); int idx = (int)lnRef.getIdx(); @@ -308,7 +306,7 @@ public abstract class XSLFSimpleShape extends XSLFShape return paint; } - + /** * * @param width line width in points. 0 means no line @@ -362,6 +360,40 @@ public abstract class XSLFSimpleShape extends XSLFShape return lineWidth; } + + /** + * @param compound set the line compound style + */ + public void setLineCompound(LineCompound compound) { + CTShapeProperties spPr = getSpPr(); + if (compound == null) { + if (spPr.isSetLn() && spPr.getLn().isSetCmpd()) + spPr.getLn().unsetCmpd(); + } else { + CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn(); + STCompoundLine.Enum xCmpd; + switch (compound) { + default: + case SINGLE: + xCmpd = STCompoundLine.SNG; + break; + case DOUBLE: + xCmpd = STCompoundLine.DBL; + break; + case THICK_THIN: + xCmpd = STCompoundLine.THICK_THIN; + break; + case THIN_THICK: + xCmpd = STCompoundLine.THIN_THICK; + break; + case TRIPLE: + xCmpd = STCompoundLine.TRI; + break; + } + ln.setCmpd(xCmpd); + } + } + /** * @return the line compound */ @@ -392,7 +424,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } } } - + if (cmpd == null) return null; switch (cmpd) { @@ -417,15 +449,12 @@ public abstract class XSLFSimpleShape extends XSLFShape public void setLineDash(LineDash dash) { CTShapeProperties spPr = getSpPr(); if (dash == null) { - if (spPr.isSetLn() && spPr.getLn().isSetPrstDash()) + if (spPr.isSetLn() && spPr.getLn().isSetPrstDash()) spPr.getLn().unsetPrstDash(); } else { - CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory - .newInstance(); - val.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId)); - CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr - .addNewLn(); - ln.setPrstDash(val); + CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn(); + CTPresetLineDashProperties ldp = ln.isSetPrstDash() ? ln.getPrstDash() : ln.addNewPrstDash(); + ldp.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId)); } } @@ -513,13 +542,7 @@ public abstract class XSLFSimpleShape extends XSLFShape return cap; } - /** - * Specifies a solid color fill. The shape is filled entirely with the - * specified color. - * - * @param color the solid color fill. The value of null unsets - * the solidFIll attribute from the underlying xml - */ + @Override public void setFillColor(Color color) { CTShapeProperties spPr = getSpPr(); if (color == null) { @@ -545,10 +568,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } } - /** - * @return solid fill color of null if not set or fill color - * is not solid (pattern or gradient) - */ + @Override public Color getFillColor() { PaintStyle ps = getFillPaint(); if (ps instanceof SolidPaint) { @@ -615,7 +635,7 @@ public abstract class XSLFSimpleShape extends XSLFShape } return geom; } - + @Override void copy(XSLFShape sh){ super.copy(sh); @@ -635,7 +655,7 @@ public abstract class XSLFSimpleShape extends XSLFShape String relId = getSheet().importBlip(blipId, s.getSheet().getPackagePart()); blip.setEmbed(relId); } - + Color srcLineColor = s.getLineColor(); Color tgtLineColor = getLineColor(); if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) { @@ -871,7 +891,31 @@ public abstract class XSLFSimpleShape extends XSLFShape public LineCompound getLineCompound() { return XSLFSimpleShape.this.getLineCompound(); } - + }; } + + @Override + public void setStrokeStyle(Object... styles) { + if (styles.length == 0) { + // remove stroke + setLineColor(null); + return; + } + + // TODO: handle PaintStyle + for (Object st : styles) { + if (st instanceof Number) { + setLineWidth(((Number)st).doubleValue()); + } else if (st instanceof LineCap) { + setLineCap((LineCap)st); + } else if (st instanceof LineDash) { + setLineDash((LineDash)st); + } else if (st instanceof LineCompound) { + setLineCompound((LineCompound)st); + } else if (st instanceof Color) { + setLineColor((Color)st); + } + } + } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java index cba6f3e614..1d0d854bda 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java @@ -25,9 +25,9 @@ import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.Drawable; import org.apache.poi.sl.usermodel.Notes; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.Slide; import org.apache.poi.util.Beta; -import org.apache.poi.util.DocumentHelper; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.drawingml.x2006.main.CTBlip; import org.openxmlformats.schemas.drawingml.x2006.main.CTGroupShapeProperties; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java index c728197083..329ebf8994 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java @@ -22,8 +22,8 @@ import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.sl.usermodel.MasterSheet; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.util.Beta; -import org.apache.poi.util.DocumentHelper; import org.apache.poi.util.Internal; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.presentationml.x2006.main.CTBackground; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java index e6f37386b0..302e064b6a 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java @@ -25,8 +25,8 @@ import org.apache.poi.POIXMLDocumentPart; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.sl.usermodel.MasterSheet; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.util.Beta; -import org.apache.poi.util.DocumentHelper; import org.apache.xmlbeans.XmlException; import org.openxmlformats.schemas.drawingml.x2006.main.CTColorMapping; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java index 7469e25d42..b30b3ba269 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java @@ -80,15 +80,22 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable iterator(){ return _rows.iterator(); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java index 29f373929e..b5dcc8e0f5 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java @@ -21,6 +21,12 @@ package org.apache.poi.xslf.usermodel; import java.awt.Color; +import org.apache.poi.sl.draw.DrawPaint; +import org.apache.poi.sl.usermodel.PaintStyle; +import org.apache.poi.sl.usermodel.StrokeStyle; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.TableCell; import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.util.Units; @@ -44,7 +50,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; * Represents a cell of a table in a .pptx presentation */ public class XSLFTableCell extends XSLFTextShape implements TableCell { - static double defaultBorderWidth = 1.0; private CTTableCellProperties _tcPr = null; /*package*/ XSLFTableCell(CTTableCell cell, XSLFSheet sheet){ @@ -57,8 +62,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell getTextRuns(){ return _runs; } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index fd0f44d75a..8ce7c5241e 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -206,12 +206,7 @@ public class XSLFTextRun implements TextRun { } } - /** - * Specifies the typeface, or name of the font that is to be used for this text run. - * - * @param typeface the font to apply to this text run. - * The value of null unsets the Typeface attrubute from the underlying xml. - */ + @Override public void setFontFamily(String typeface){ setFontFamily(typeface, (byte)-1, (byte)-1, false); } @@ -236,9 +231,7 @@ public class XSLFTextRun implements TextRun { } } - /** - * @return font family or null if not set - */ + @Override public String getFontFamily(){ final XSLFTheme theme = _p.getParentShape().getSheet().getTheme(); @@ -281,18 +274,12 @@ public class XSLFTextRun implements TextRun { return visitor.getValue() == null ? 0 : visitor.getValue(); } - /** - * Specifies whether a run of text will be formatted as strikethrough text. - * - * @param strike whether a run of text will be formatted as strikethrough text. - */ + @Override public void setStrikethrough(boolean strike) { getRPr().setStrike(strike ? STTextStrikeType.SNG_STRIKE : STTextStrikeType.NO_STRIKE); } - /** - * @return whether a run of text will be formatted as strikethrough text. Default is false. - */ + @Override public boolean isStrikethrough() { CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -307,9 +294,7 @@ public class XSLFTextRun implements TextRun { return fetcher.getValue() == null ? false : fetcher.getValue(); } - /** - * @return whether a run of text will be formatted as a superscript text. Default is false. - */ + @Override public boolean isSuperscript() { CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -357,9 +342,7 @@ public class XSLFTextRun implements TextRun { setBaselineOffset(flag ? -25.0 : 0.); } - /** - * @return whether a run of text will be formatted as a superscript text. Default is false. - */ + @Override public boolean isSubscript() { CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -392,18 +375,12 @@ public class XSLFTextRun implements TextRun { return fetcher.getValue() == null ? TextCap.NONE : fetcher.getValue(); } - /** - * Specifies whether this run of text will be formatted as bold text - * - * @param bold whether this run of text will be formatted as bold text - */ + @Override public void setBold(boolean bold){ getRPr().setB(bold); } - /** - * @return whether this run of text is formatted as bold text - */ + @Override public boolean isBold(){ CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -418,16 +395,12 @@ public class XSLFTextRun implements TextRun { return fetcher.getValue() == null ? false : fetcher.getValue(); } - /** - * @param italic whether this run of text is formatted as italic text - */ + @Override public void setItalic(boolean italic){ getRPr().setI(italic); } - /** - * @return whether this run of text is formatted as italic text - */ + @Override public boolean isItalic(){ CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -442,16 +415,12 @@ public class XSLFTextRun implements TextRun { return fetcher.getValue() == null ? false : fetcher.getValue(); } - /** - * @param underline whether this run of text is formatted as underlined text - */ - public void setUnderline(boolean underline) { + @Override + public void setUnderlined(boolean underline) { getRPr().setU(underline ? STTextUnderlineType.SNG : STTextUnderlineType.NONE); } - /** - * @return whether this run of text is formatted as underlined text - */ + @Override public boolean isUnderlined(){ CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getIndentLevel()){ public boolean fetch(CTTextCharacterProperties props){ @@ -501,6 +470,7 @@ public class XSLFTextRun implements TextRun { CTPlaceholder ph = shape.getCTPlaceholder(); if (ph == null){ // if it is a plain text box then take defaults from presentation.xml + @SuppressWarnings("resource") XMLSlideShow ppt = sheet.getSlideShow(); CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel()); if (themeProps != null) { @@ -543,7 +513,7 @@ public class XSLFTextRun implements TextRun { if(italic != isItalic()) setItalic(italic); boolean underline = r.isUnderlined(); - if(underline != isUnderlined()) setUnderline(underline); + if(underline != isUnderlined()) setUnderlined(underline); boolean strike = r.isStrikethrough(); if(strike != isStrikethrough()) setStrikethrough(strike); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java index 8cc90f979f..8a4a935209 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java @@ -37,8 +37,10 @@ import org.apache.poi.xslf.model.TextBodyPropertyFetcher; import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextListStyle; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; +import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextVerticalType; import org.openxmlformats.schemas.drawingml.x2006.main.STTextWrappingType; @@ -91,10 +93,52 @@ public abstract class XSLFTextShape extends XSLFSimpleShape txBody.setPArray(null); // remove any existing paragraphs } - public void setText(String text){ - clearText(); + @Override + public XSLFTextRun setText(String text) { + // copy properties from first paragraph / textrun + CTTextParagraphProperties pPr = null; + CTTextCharacterProperties rPr = null; + if (!_paragraphs.isEmpty()) { + XSLFTextParagraph p0 = _paragraphs.get(0); + pPr = p0.getXmlObject().getPPr(); + if (!p0.getTextRuns().isEmpty()) { + XSLFTextRun r0 = p0.getTextRuns().get(0); + rPr = r0.getXmlObject().getRPr(); + } + } - addNewTextParagraph().addNewTextRun().setText(text); + // can't call clearText otherwise we receive a XmlValueDisconnectedException + _paragraphs.clear(); + CTTextBody txBody = getTextBody(true); + int cntPs = txBody.sizeOfPArray(); + + // split text by paragraph and new line char + XSLFTextRun r = null; + for (String paraText : text.split("\\r\\n?|\\n")) { + XSLFTextParagraph para = addNewTextParagraph(); + if (pPr != null) { + para.getXmlObject().setPPr(pPr); + } + boolean first = true; + for (String runText : paraText.split("[\u000b]")) { + if (!first) { + para.addLineBreak(); + } + r = para.addNewTextRun(); + r.setText(runText); + if (rPr != null) { + r.getXmlObject().setRPr(rPr); + } + first = false; + } + } + + // simply setting a new pArray leads to XmlValueDisconnectedException + for (int i = cntPs-1; i >= 0; i--) { + txBody.removeP(i); + } + + return r; } @Override @@ -115,13 +159,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape return paragraph; } - - /** - * Sets the type of vertical alignment for the text. - * - * @param anchor - the type of alignment. - * A {@code null} values unsets this property. - */ + @Override public void setVerticalAlignment(VerticalAlignment anchor){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { @@ -133,11 +171,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape } } - /** - * Returns the type of vertical alignment for the text. - * - * @return the type of vertical alignment - */ + @Override public VerticalAlignment getVerticalAlignment(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ @@ -153,14 +187,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape return fetcher.getValue() == null ? VerticalAlignment.TOP : fetcher.getValue(); } - /** - * Sets if the paragraphs are horizontal centered - * - * @param isCentered true, if the paragraphs are horizontal centered - * A {@code null} values unsets this property. - * - * @see TextShape#isHorizontalCentered() - */ + @Override public void setHorizontalCentered(Boolean isCentered){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { @@ -369,10 +396,15 @@ public abstract class XSLFTextShape extends XSLFSimpleShape return insets; } - - /** - * @return whether to wrap words within the bounding rectangle - */ + @Override + public void setInsets(Insets2D insets) { + setTopInset(insets.top); + setLeftInset(insets.left); + setBottomInset(insets.bottom); + setRightInset(insets.right); + } + + @Override public boolean getWordWrap(){ PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ public boolean fetch(CTTextBodyProperties props){ @@ -387,10 +419,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape return fetcher.getValue() == null ? true : fetcher.getValue(); } - /** - * - * @param wrap whether to wrap words within the bounding rectangle - */ + @Override public void setWordWrap(boolean wrap){ CTTextBodyProperties bodyPr = getTextBodyPr(); if (bodyPr != null) { @@ -532,4 +561,45 @@ public abstract class XSLFTextShape extends XSLFSimpleShape tgtP.copy(srcP); } } + + @Override + public void setTextPlaceholder(TextPlaceholder placeholder) { + switch (placeholder) { + default: + case NOTES: + case HALF_BODY: + case QUARTER_BODY: + case BODY: + setPlaceholder(Placeholder.BODY); + break; + case TITLE: + setPlaceholder(Placeholder.TITLE); + break; + case CENTER_BODY: + setPlaceholder(Placeholder.BODY); + setHorizontalCentered(true); + break; + case CENTER_TITLE: + setPlaceholder(Placeholder.CENTERED_TITLE); + break; + case OTHER: + setPlaceholder(Placeholder.CONTENT); + break; + } + } + + @Override + public TextPlaceholder getTextPlaceholder() { + Placeholder ph = getTextType(); + if (ph == null) return TextPlaceholder.BODY; + switch (ph) { + case BODY: return TextPlaceholder.BODY; + case TITLE: return TextPlaceholder.TITLE; + case CENTERED_TITLE: return TextPlaceholder.CENTER_TITLE; + default: + case CONTENT: return TextPlaceholder.OTHER; + } + } + + } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java index 3350149751..525f55ef7b 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java @@ -268,7 +268,7 @@ public class TestXSLFAutoShape { assertFalse(r.isUnderlined()); assertFalse(r.getXmlObject().getRPr().isSetU()); - r.setUnderline(true); + r.setUnderlined(true); assertTrue(r.isUnderlined()); assertEquals(STTextUnderlineType.SNG, r.getXmlObject().getRPr().getU()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFNotes.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFNotes.java index 0eb075acaf..02fac93bc8 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFNotes.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFNotes.java @@ -20,13 +20,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import java.io.IOException; + +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.xslf.XSLFTestDataSamples; import org.junit.Test; public class TestXSLFNotes { @Test - public void createNewNote() { + public void createNewNote() throws IOException { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide1 = ppt.createSlide(); @@ -48,10 +51,12 @@ public class TestXSLFNotes { } assertNotNull(note); assertEquals("New Note", note); + + ppt.close(); } @Test - public void addNote() { + public void addNote() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx"); @@ -69,10 +74,12 @@ public class TestXSLFNotes { } assertNotNull(note); assertEquals("New Note", note); + + ppt.close(); } @Test - public void replaceNotes() { + public void replaceNotes() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx"); @@ -93,5 +100,7 @@ public class TestXSLFNotes { assertNotNull(note); assertEquals("New Note", note); } + + ppt.close(); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java index db2c9833f7..452f22ebcb 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java @@ -28,6 +28,7 @@ import java.io.IOException; import java.util.List; import org.apache.poi.sl.draw.geom.TestPresetGeometries; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.util.Units; @@ -168,7 +169,7 @@ public class TestXSLFSimpleShape { } @Test - public void testDefaultProperties() { + public void testDefaultProperties() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); XSLFSlide slide6 = ppt.getSlides().get(5); @@ -234,10 +235,12 @@ public class TestXSLFSimpleShape { assertEquals(50000, ref5.getLumModArray(0).getVal()); assertEquals("accent1", ref5.getVal().toString()); assertEquals(new Color(79, 129, 189), s5.getFillColor()); + + ppt.close(); } @Test - public void testAnchor(){ + public void testAnchor() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); List slide = ppt.getSlides(); @@ -267,6 +270,7 @@ public class TestXSLFSimpleShape { assertNotNull(layout5.getSlideMaster().getTextShapeByType(Placeholder.TITLE).getSpPr().getXfrm()); assertEquals(shTitle.getAnchor(), layout5.getSlideMaster().getTextShapeByType(Placeholder.TITLE).getAnchor()); + ppt.close(); } @SuppressWarnings({ "deprecation", "unused" }) diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java index 3b7c5cbcc2..cf535b5650 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java @@ -16,23 +16,29 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; +import java.awt.Color; +import java.io.IOException; +import java.util.List; + +import org.apache.poi.sl.usermodel.TableCell.BorderEdge; import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.xslf.XSLFTestDataSamples; import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; -import java.awt.Color; -import java.util.List; - /** * @author Yegor Kozlov */ public class TestXSLFTable { @Test - public void testRead(){ + public void testRead() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); XSLFSlide slide = ppt.getSlides().get(3); @@ -69,10 +75,12 @@ public class TestXSLFTable { assertEquals("A1", cells1.get(0).getText()); assertEquals("B1", cells1.get(1).getText()); assertEquals("C1", cells1.get(2).getText()); + + ppt.close(); } @Test - public void testCreate() { + public void testCreate() throws IOException { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -121,38 +129,21 @@ public class TestXSLFTable { cell1.addNewTextParagraph().addNewTextRun().setText("Apache"); assertEquals("Apache", cell1.getText()); - assertEquals(1.0, cell1.getBorderBottom(), 0); - cell1.setBorderBottom(2.0); - assertEquals(2.0, cell1.getBorderBottom(), 0); - assertNull(cell1.getBorderBottomColor()); - cell1.setBorderBottomColor(Color.yellow); - assertEquals(Color.yellow, cell1.getBorderBottomColor()); - - assertEquals(1.0, cell1.getBorderTop(), 0); - cell1.setBorderTop(2.0); - assertEquals(2.0, cell1.getBorderTop(), 0); - assertNull(cell1.getBorderTopColor()); - cell1.setBorderTopColor(Color.yellow); - assertEquals(Color.yellow, cell1.getBorderTopColor()); - - assertEquals(1.0, cell1.getBorderLeft(), 0); - cell1.setBorderLeft(2.0); - assertEquals(2.0, cell1.getBorderLeft(), 0); - assertNull(cell1.getBorderLeftColor()); - cell1.setBorderLeftColor(Color.yellow); - assertEquals(Color.yellow, cell1.getBorderLeftColor()); - - assertEquals(1.0, cell1.getBorderRight(), 0); - cell1.setBorderRight(2.0); - assertEquals(2.0, cell1.getBorderRight(), 0); - assertNull(cell1.getBorderRightColor()); - cell1.setBorderRightColor(Color.yellow); - assertEquals(Color.yellow, cell1.getBorderRightColor()); + for (BorderEdge edge : BorderEdge.values()) { + assertNull(cell1.getBorderWidth(edge)); + cell1.setBorderWidth(edge, 2.0); + assertEquals(2.0, cell1.getBorderWidth(edge), 0); + assertNull(cell1.getBorderColor(edge)); + cell1.setBorderColor(edge, Color.yellow); + assertEquals(Color.yellow, cell1.getBorderColor(edge)); + } assertEquals(VerticalAlignment.TOP, cell1.getVerticalAlignment()); cell1.setVerticalAlignment(VerticalAlignment.MIDDLE); assertEquals(VerticalAlignment.MIDDLE, cell1.getVerticalAlignment()); cell1.setVerticalAlignment(null); assertEquals(VerticalAlignment.TOP, cell1.getVerticalAlignment()); + + ppt.close(); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java index 59b0dca95c..cee11e541a 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java @@ -19,6 +19,9 @@ package org.apache.poi.xslf.usermodel; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; +import java.io.IOException; + +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; @@ -28,7 +31,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties public class TestXSLFTextBox { @Test - public void testPlaceholder() { + public void testPlaceholder() throws IOException { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -39,13 +42,15 @@ public class TestXSLFTextBox { shape.setPlaceholder(null); assertNull(shape.getTextType()); shape.setText("Apache POI"); + + ppt.close(); } /** * text box inherits default text proeprties from presentation.xml */ @Test - public void testDefaultTextStyle() { + public void testDefaultTextStyle() throws IOException { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -79,5 +84,7 @@ public class TestXSLFTextBox { pPr.unsetSz(); // Should never be assertNull(r.getFontSize()); + + ppt.close(); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java index e0c4f9dd96..18632ffbf0 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java @@ -28,6 +28,7 @@ import java.awt.Color; import java.io.IOException; import java.util.List; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.xslf.XSLFTestDataSamples; @@ -45,7 +46,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; public class TestXSLFTextShape { @Test - public void testLayouts(){ + public void testLayouts() throws IOException { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx"); List slide = ppt.getSlides(); @@ -57,6 +58,8 @@ public class TestXSLFTextShape { verifySlide7(slide.get(6)); verifySlide8(slide.get(7)); verifySlide10(slide.get(9)); + + ppt.close(); } void verifySlide1(XSLFSlide slide){ diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java index 834dea5ff0..0022822b82 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java @@ -297,7 +297,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { txt.setTopInset(0); txt.setLeftInset(0); txt.setRightInset(0); - txt.setWordWrap(HSLFTextBox.WrapNone); + txt.setWordWrap(false); txt.setHorizontalCentered(false); txt.setVerticalAlignment(VerticalAlignment.MIDDLE); @@ -1826,7 +1826,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { float[] dash = bs.getDashArray(); if (dash != null) { //TODO: implement more dashing styles - shape.setLineDashing(StrokeStyle.LineDash.DASH); + shape.setLineDash(StrokeStyle.LineDash.DASH); } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java b/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java deleted file mode 100644 index 1e632b8dcc..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java +++ /dev/null @@ -1,96 +0,0 @@ -/* ==================================================================== - Licensed to the Apache Software Foundation (ASF) under one or more - contributor license agreements. See the NOTICE file distributed with - this work for additional information regarding copyright ownership. - The ASF licenses this file to You under the Apache License, Version 2.0 - (the "License"); you may not use this file except in compliance with - the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -==================================================================== */ - -package org.apache.poi.hslf.model; - -import org.apache.poi.ddf.*; -import org.apache.poi.hslf.record.OEPlaceholderAtom; -import org.apache.poi.hslf.usermodel.HSLFShape; -import org.apache.poi.hslf.usermodel.HSLFTextBox; -import org.apache.poi.hslf.usermodel.HSLFTextParagraph; -import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.sl.usermodel.ShapeContainer; - -import java.io.ByteArrayOutputStream; - -/** - * Represents a Placeholder in PowerPoint. - * - * @author Yegor Kozlov - */ -public final class Placeholder extends HSLFTextBox { - - protected Placeholder(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - } - - public Placeholder(ShapeContainer parent){ - super(parent); - } - - public Placeholder(){ - super(); - } - - /** - * Create a new Placeholder and initialize internal structures - * - * @return the created EscherContainerRecord which holds shape data - */ - protected EscherContainerRecord createSpContainer(boolean isChild){ - _escherContainer = super.createSpContainer(isChild); - - EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); - spRecord.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER); - - EscherClientDataRecord cldata = new EscherClientDataRecord(); - cldata.setOptions((short)15); - - AbstractEscherOptRecord opt = getEscherOptRecord(); - - //Placeholders can't be grouped - setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 262144); - - //OEPlaceholderAtom tells powerpoint that this shape is a placeholder - // - OEPlaceholderAtom oep = new OEPlaceholderAtom(); - /** - * Extarct from MSDN: - * - * There is a special case when the placeholder does not have a position in the layout. - * This occurs when the user has moved the placeholder from its original position. - * In this case the placeholder ID is -1. - */ - oep.setPlacementId(-1); - - oep.setPlaceholderId(OEPlaceholderAtom.Body); - - //convert hslf into ddf record - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - oep.writeOut(out); - } catch(Exception e){ - throw new HSLFException(e); - } - cldata.setRemainingData(out.toByteArray()); - - //append placeholder container before EscherTextboxRecord - _escherContainer.addChildBefore(cldata, EscherTextboxRecord.RECORD_ID); - - return _escherContainer; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java index 21c07010ca..329f78f423 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java @@ -67,7 +67,7 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape { - /** * Create a new ShapeGroup. This constructor is used when a new shape is created. * @@ -73,34 +72,16 @@ implements HSLFShapeContainer, GroupShape { super(escherRecord, parent); } - /** - * Sets the anchor (the bounding box rectangle) of this shape. - * All coordinates should be expressed in Master units (576 dpi). - * - * @param anchor new anchor - */ - public void setAnchor(java.awt.Rectangle anchor){ - + @Override + public void setAnchor(Rectangle anchor) { EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); - //hack. internal variable EscherClientAnchorRecord.shortRecord can be - //initialized only in fillFields(). We need to set shortRecord=false; - byte[] header = new byte[16]; - LittleEndian.putUShort(header, 0, 0); - LittleEndian.putUShort(header, 2, 0); - LittleEndian.putInt(header, 4, 8); - clientAnchor.fillFields(header, 0, null); - - clientAnchor.setFlag((short)Units.pointsToMaster(anchor.y)); - clientAnchor.setCol1((short)Units.pointsToMaster(anchor.x)); - clientAnchor.setDx1((short)Units.pointsToMaster(anchor.width + anchor.x)); - clientAnchor.setRow1((short)Units.pointsToMaster(anchor.height + anchor.y)); - - EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); - - spgr.setRectX1(Units.pointsToMaster(anchor.x)); - spgr.setRectY1(Units.pointsToMaster(anchor.y)); - spgr.setRectX2(Units.pointsToMaster(anchor.x + anchor.width)); - spgr.setRectY2(Units.pointsToMaster(anchor.y + anchor.height)); + boolean isInitialized = !(clientAnchor.getDx1() == 0 && clientAnchor.getRow1() == 0); + + if (isInitialized) { + moveAndScale(anchor); + } else { + setExteriorAnchor(anchor); + } } @Override @@ -116,7 +97,6 @@ implements HSLFShapeContainer, GroupShape { spgr.setRectY1(y1); spgr.setRectX2(x2); spgr.setRectY2(y2); - } @Override @@ -129,6 +109,27 @@ implements HSLFShapeContainer, GroupShape { return new Rectangle(x1,y1,x2-x1,y2-y1); } + protected void setExteriorAnchor(Rectangle anchor) { + EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); + + //hack. internal variable EscherClientAnchorRecord.shortRecord can be + //initialized only in fillFields(). We need to set shortRecord=false; + byte[] header = new byte[16]; + LittleEndian.putUShort(header, 0, 0); + LittleEndian.putUShort(header, 2, 0); + LittleEndian.putInt(header, 4, 8); + clientAnchor.fillFields(header, 0, null); + + // All coordinates need to be converted to Master units (576 dpi) + clientAnchor.setFlag((short)Units.pointsToMaster(anchor.y)); + clientAnchor.setCol1((short)Units.pointsToMaster(anchor.x)); + clientAnchor.setDx1((short)Units.pointsToMaster(anchor.width + anchor.x)); + clientAnchor.setRow1((short)Units.pointsToMaster(anchor.height + anchor.y)); + + // TODO: does this make sense? + setInteriorAnchor(anchor); + } + /** * Create a new ShapeGroup and create an instance of EscherSpgrContainer which represents a group of shapes */ @@ -174,23 +175,22 @@ implements HSLFShapeContainer, GroupShape { } /** - * Moves this ShapeGroup to the specified location. - *

- * @param x the x coordinate of the top left corner of the shape in new location - * @param y the y coordinate of the top left corner of the shape in new location + * Moves and scales this ShapeGroup to the specified anchor. */ - public void moveTo(int x, int y){ - Rectangle anchor = getAnchor(); - int dx = x - anchor.x; - int dy = y - anchor.y; - anchor.translate(dx, dy); - setAnchor(anchor); + protected void moveAndScale(Rectangle anchorDest){ + Rectangle anchorSrc = getAnchor(); + double scaleX = (anchorSrc.width == 0) ? 0 : anchorDest.width / (double)anchorSrc.width; + double scaleY = (anchorSrc.height == 0) ? 0 : anchorDest.height / (double)anchorSrc.height; + setExteriorAnchor(anchorDest); for (HSLFShape shape : getShapes()) { Rectangle chanchor = shape.getAnchor(); - chanchor.translate(dx, dy); - shape.setAnchor(chanchor); + int x = (int)Math.rint(anchorDest.x+(chanchor.x-anchorSrc.x)*scaleX); + int y = (int)Math.rint(anchorDest.y+(chanchor.y-anchorSrc.y)*scaleY); + int width = (int)Math.rint(chanchor.width*scaleX); + int height = (int)Math.rint(chanchor.height*scaleY); + shape.setAnchor(new Rectangle(x, y, width, height)); } } @@ -262,9 +262,6 @@ implements HSLFShapeContainer, GroupShape { throw new UnsupportedOperationException(); } - /** - * @return the shapes contained in this group container - */ @Override public List getShapes() { // Out escher container record should contain several diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholder.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholder.java new file mode 100644 index 0000000000..c0a7aef69e --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholder.java @@ -0,0 +1,55 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.hslf.usermodel; + +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.sl.usermodel.SimpleShape.Placeholder; +import org.apache.poi.sl.usermodel.ShapeContainer; + +/** + * Represents a Placeholder in PowerPoint. + * + * @author Yegor Kozlov + */ +public final class HSLFPlaceholder extends HSLFTextBox { + + protected HSLFPlaceholder(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + } + + public HSLFPlaceholder(ShapeContainer parent){ + super(parent); + } + + public HSLFPlaceholder(){ + super(); + } + + /** + * Create a new Placeholder and initialize internal structures + * + * @return the created EscherContainerRecord which holds shape data + */ + protected EscherContainerRecord createSpContainer(boolean isChild){ + _escherContainer = super.createSpContainer(isChild); + + setPlaceholder(Placeholder.BODY); + + return _escherContainer; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java index 85f3a906ea..81679c02df 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java @@ -116,19 +116,11 @@ public abstract class HSLFShape implements Shape { return getShapeType().nativeName; } - /** - * @return type of the shape. - * @see org.apache.poi.hslf.record.RecordTypes - */ public ShapeType getShapeType(){ EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); return ShapeType.forId(spRecord.getShapeType(), false); } - /** - * @param type type of the shape. - * @see org.apache.poi.hslf.record.RecordTypes - */ public void setShapeType(ShapeType type){ EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); spRecord.setShapeType( (short) type.nativeId ); @@ -209,7 +201,9 @@ public abstract class HSLFShape implements Shape { * @param x the x coordinate of the top left corner of the shape * @param y the y coordinate of the top left corner of the shape */ - public void moveTo(float x, float y){ + public final void moveTo(float x, float y) { + // This convenience method should be implemented via setAnchor in subclasses + // see HSLFGroupShape.setAnchor() for a reference Rectangle anchor = getAnchor(); anchor.setRect(x, y, anchor.getWidth(), anchor.getHeight()); setAnchor(anchor); diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java index f2aac4da25..4fe197782e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java @@ -56,7 +56,7 @@ public final class HSLFShapeFactory { EscherPropertyFactory f = new EscherPropertyFactory(); List props = f.createProperties( opt.serialize(), 8, opt.getInstance() ); for (EscherProperty ep : props) { - if (ep.getPropertyNumber() == 0x39F + if (ep.getPropertyNumber() == EscherProperties.GROUPSHAPE__TABLEPROPERTIES && ep instanceof EscherSimpleProperty && ((EscherSimpleProperty)ep).getPropertyValue() == 1) { isTable = true; @@ -65,9 +65,13 @@ public final class HSLFShapeFactory { } } - HSLFGroupShape group = (isTable) - ? new HSLFTable(spContainer, parent) - : new HSLFGroupShape(spContainer, parent); + HSLFGroupShape group; + if (isTable) { + group = new HSLFTable(spContainer, parent); + + } else { + group = new HSLFGroupShape(spContainer, parent); + } return group; } @@ -82,65 +86,73 @@ public final class HSLFShapeFactory { shape = new HSLFTextBox(spContainer, parent); break; case HOST_CONTROL: - case FRAME: { - InteractiveInfo info = getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID); - OEShapeAtom oes = getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID); - if(info != null && info.getInteractiveInfoAtom() != null){ - switch(info.getInteractiveInfoAtom().getAction()){ - case InteractiveInfoAtom.ACTION_OLE: - shape = new OLEShape(spContainer, parent); - break; - case InteractiveInfoAtom.ACTION_MEDIA: - shape = new MovieShape(spContainer, parent); - break; - default: - break; - } - } else if (oes != null){ - shape = new OLEShape(spContainer, parent); - } - - if(shape == null) shape = new HSLFPictureShape(spContainer, parent); + case FRAME: + shape = createFrame(spContainer, parent); break; - } case LINE: shape = new HSLFLine(spContainer, parent); break; - case NOT_PRIMITIVE: { - AbstractEscherOptRecord opt = HSLFShape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID); - EscherProperty prop = HSLFShape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES); - if(prop != null) - shape = new HSLFFreeformShape(spContainer, parent); - else { - logger.log(POILogger.INFO, "Creating AutoShape for a NotPrimitive shape"); - shape = new HSLFAutoShape(spContainer, parent); - } + case NOT_PRIMITIVE: + shape = createNonPrimitive(spContainer, parent); break; - } default: - shape = new HSLFAutoShape(spContainer, parent); + EscherTextboxRecord etr = spContainer.getChildById(EscherTextboxRecord.RECORD_ID); + if (parent instanceof HSLFTable && etr != null) { + shape = new HSLFTableCell(spContainer, (HSLFTable)parent); + } else { + shape = new HSLFAutoShape(spContainer, parent); + } break; } return shape; - } + private static HSLFShape createFrame(EscherContainerRecord spContainer, ShapeContainer parent) { + InteractiveInfo info = getClientDataRecord(spContainer, RecordTypes.InteractiveInfo.typeID); + if(info != null && info.getInteractiveInfoAtom() != null){ + switch(info.getInteractiveInfoAtom().getAction()){ + case InteractiveInfoAtom.ACTION_OLE: + return new OLEShape(spContainer, parent); + case InteractiveInfoAtom.ACTION_MEDIA: + return new MovieShape(spContainer, parent); + default: + break; + } + } + + OEShapeAtom oes = getClientDataRecord(spContainer, RecordTypes.OEShapeAtom.typeID); + if (oes != null){ + return new OLEShape(spContainer, parent); + } + + return new HSLFPictureShape(spContainer, parent); + } + + private static HSLFShape createNonPrimitive(EscherContainerRecord spContainer, ShapeContainer parent) { + AbstractEscherOptRecord opt = HSLFShape.getEscherChild(spContainer, EscherOptRecord.RECORD_ID); + EscherProperty prop = HSLFShape.getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES); + if(prop != null) { + return new HSLFFreeformShape(spContainer, parent); + } + + logger.log(POILogger.INFO, "Creating AutoShape for a NotPrimitive shape"); + return new HSLFAutoShape(spContainer, parent); + } + @SuppressWarnings("unchecked") protected static T getClientDataRecord(EscherContainerRecord spContainer, int recordType) { - Record oep = null; for (Iterator it = spContainer.getChildIterator(); it.hasNext();) { EscherRecord obj = it.next(); if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) { byte[] data = obj.serialize(); - Record[] records = Record.findChildRecords(data, 8, data.length - 8); - for (int j = 0; j < records.length; j++) { - if (records[j].getRecordType() == recordType) { - return (T)records[j]; + for (Record r : Record.findChildRecords(data, 8, data.length - 8)) { + if (r.getRecordType() == recordType) { + return (T)r; } } } } - return (T)oep; + return null; } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java index 139840c548..1a46a5e175 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java @@ -458,7 +458,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet getShadow() { AbstractEscherOptRecord opt = getEscherOptRecord(); EscherProperty shadowType = opt.lookup(EscherProperties.SHADOWSTYLE__TYPE); if (shadowType == null) return null; - + return new Shadow(){ public SimpleShape getShadowParent() { return HSLFSimpleShape.this; @@ -443,7 +459,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShapeTextBox object that represents the slide's title. */ public HSLFTextBox addTitle() { - Placeholder pl = new Placeholder(); + HSLFPlaceholder pl = new HSLFPlaceholder(); pl.setShapeType(ShapeType.RECT); pl.setRunType(TextHeaderAtom.TITLE_TYPE); pl.setText("Click to edit title"); diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java index 7064a862bf..46a356fec9 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java @@ -531,9 +531,7 @@ public final class HSLFSlideShow implements SlideShow { - protected static final int BORDER_TOP = 1; - protected static final int BORDER_RIGHT = 2; - protected static final int BORDER_BOTTOM = 3; - protected static final int BORDER_LEFT = 4; - protected static final int BORDERS_ALL = 5; protected static final int BORDERS_OUTSIDE = 6; protected static final int BORDERS_INSIDE = 7; @@ -65,10 +59,10 @@ implements HSLFShapeContainer, TableShape { * @param numRows the number of rows * @param numCols the number of columns */ - public HSLFTable(int numRows, int numCols) { + protected HSLFTable(int numRows, int numCols) { this(numRows, numCols, null); } - + /** * Create a new Table of the given number of rows and columns * @@ -76,7 +70,7 @@ implements HSLFShapeContainer, TableShape { * @param numCols the number of columns * @param parent the parent shape, or null if table is added to sheet */ - public HSLFTable(int numRows, int numCols, ShapeContainer parent) { + protected HSLFTable(int numRows, int numCols, ShapeContainer parent) { super(parent); if(numRows < 1) throw new IllegalArgumentException("The number of rows must be greater than 1"); @@ -96,13 +90,13 @@ implements HSLFShapeContainer, TableShape { } tblWidth = x; tblHeight = y; - setAnchor(new Rectangle(0, 0, tblWidth, tblHeight)); + setExteriorAnchor(new Rectangle(0, 0, tblWidth, tblHeight)); EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); AbstractEscherOptRecord opt = new EscherOptRecord(); opt.setRecordId((short)RecordTypes.EscherUserDefined); - opt.addEscherProperty(new EscherSimpleProperty((short)0x39F, 1)); - EscherArrayProperty p = new EscherArrayProperty((short)(0x4000 | 0x3A0), false, null); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GROUPSHAPE__TABLEPROPERTIES, 1)); + EscherArrayProperty p = new EscherArrayProperty((short)(0x4000 | EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES), false, null); p.setSizeOfElements(0x0004); p.setNumberOfElementsInArray(numRows); p.setNumberOfElementsInMemory(numRows); @@ -111,12 +105,12 @@ implements HSLFShapeContainer, TableShape { } /** - * Create a Table object and initilize it from the supplied Record container. + * Create a Table object and initialize it from the supplied Record container. * * @param escherRecord EscherSpContainer container which holds information about this shape * @param parent the parent of the shape */ - public HSLFTable(EscherContainerRecord escherRecord, ShapeContainer parent) { + protected HSLFTable(EscherContainerRecord escherRecord, ShapeContainer parent) { super(escherRecord, parent); } @@ -131,9 +125,12 @@ implements HSLFShapeContainer, TableShape { return cells[row][col]; } + @Override public int getNumberOfColumns() { return cells[0].length; } + + @Override public int getNumberOfRows() { return cells.length; } @@ -141,90 +138,171 @@ implements HSLFShapeContainer, TableShape { protected void afterInsert(HSLFSheet sh){ super.afterInsert(sh); - EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0); - List lst = spCont.getChildRecords(); - AbstractEscherOptRecord opt = (AbstractEscherOptRecord)lst.get(lst.size()-2); - EscherArrayProperty p = opt.lookup(0x3A0); - for (int i = 0; i < cells.length; i++) { - HSLFTableCell cell = cells[i][0]; - int rowHeight = Units.pointsToMaster(cell.getAnchor().height); - byte[] val = new byte[4]; - LittleEndian.putInt(val, 0, rowHeight); - p.setElement(i, val); - for (int j = 0; j < cells[i].length; j++) { - HSLFTableCell c = cells[i][j]; + Set lineSet = new HashSet(); + for (HSLFTableCell row[] : cells) { + for (HSLFTableCell c : row) { addShape(c); + for (HSLFLine bt : new HSLFLine[]{ c.borderTop, c.borderRight, c.borderBottom, c.borderLeft }) { + if (bt != null) { + lineSet.add(bt); + } + } + } + } + + for (HSLFLine l : lineSet) { + addShape(l); + } - HSLFLine bt = c.getBorderTop(); - if(bt != null) addShape(bt); + updateRowHeightsProperty(); + } + + private static class TableCellComparator implements Comparator { + public int compare( HSLFShape o1, HSLFShape o2 ) { + Rectangle anchor1 = o1.getAnchor(); + Rectangle anchor2 = o2.getAnchor(); + int delta = anchor1.y - anchor2.y; + if (delta == 0) delta = anchor1.x - anchor2.x; + // descending size + if (delta == 0) delta = (anchor2.width*anchor2.height)-(anchor1.width*anchor1.height); + return delta; + } + } - HSLFLine br = c.getBorderRight(); - if(br != null) addShape(br); + private void cellListToArray() { + List htc = new ArrayList(); + for (HSLFShape h : getShapes()) { + if (h instanceof HSLFTableCell) { + htc.add((HSLFTableCell)h); + } + } + + if (htc.isEmpty()) { + throw new IllegalStateException("HSLFTable without HSLFTableCells"); + } - HSLFLine bb = c.getBorderBottom(); - if(bb != null) addShape(bb); + Collections.sort(htc, new TableCellComparator()); - HSLFLine bl = c.getBorderLeft(); - if(bl != null) addShape(bl); + List lst = new ArrayList(); + List row = new ArrayList(); + int y0 = htc.get(0).getAnchor().y; + for (HSLFTableCell sh : htc) { + Rectangle anchor = sh.getAnchor(); + boolean isNextRow = (anchor.y > y0); + if (isNextRow) { + y0 = anchor.y; + lst.add(row.toArray(new HSLFTableCell[row.size()])); + row.clear(); } + row.add(sh); } + lst.add(row.toArray(new HSLFTableCell[row.size()])); + cells = lst.toArray(new HSLFTableCell[lst.size()][]); } - protected void initTable(){ - List shapeList = getShapes(); - - Iterator shapeIter = shapeList.iterator(); - while (shapeIter.hasNext()) { - HSLFShape shape = shapeIter.next(); - if (shape instanceof HSLFAutoShape) { - HSLFAutoShape autoShape = (HSLFAutoShape)shape; - EscherTextboxRecord etr = autoShape.getEscherChild(EscherTextboxRecord.RECORD_ID); - if (etr != null) continue; - } - shapeIter.remove(); - } - - Collections.sort(shapeList, new Comparator(){ - public int compare( HSLFShape o1, HSLFShape o2 ) { - Rectangle anchor1 = o1.getAnchor(); - Rectangle anchor2 = o2.getAnchor(); - int delta = anchor1.y - anchor2.y; - if (delta == 0) delta = anchor1.x - anchor2.x; - // descending size - if (delta == 0) delta = (anchor2.width*anchor2.height)-(anchor1.width*anchor1.height); - return delta; - } - }); - - int y0 = (shapeList.isEmpty()) ? -1 : shapeList.get(0).getAnchor().y - 1; - int maxrowlen = 0; - List> lst = new ArrayList>(); - List row = null; - for (HSLFShape sh : shapeList) { - if(sh instanceof HSLFTextShape){ - Rectangle anchor = sh.getAnchor(); - if(anchor.y != y0){ - y0 = anchor.y; - row = new ArrayList(); - lst.add(row); - } - row.add(sh); - maxrowlen = Math.max(maxrowlen, row.size()); + static class LineRect { + final HSLFLine l; + final double lx1, lx2, ly1, ly2; + LineRect(HSLFLine l) { + this.l = l; + Rectangle r = l.getAnchor(); + lx1 = r.getMinX(); + lx2 = r.getMaxX(); + ly1 = r.getMinY(); + ly2 = r.getMaxY(); + } + int leftFit(double x1, double x2, double y1, double y2) { + return (int)(Math.abs(x1-lx1)+Math.abs(y1-ly1)+Math.abs(x1-lx2)+Math.abs(y2-ly2)); + } + int topFit(double x1, double x2, double y1, double y2) { + return (int)(Math.abs(x1-lx1)+Math.abs(y1-ly1)+Math.abs(x2-lx2)+Math.abs(y1-ly2)); + } + int rightFit(double x1, double x2, double y1, double y2) { + return (int)(Math.abs(x2-lx1)+Math.abs(y1-ly1)+Math.abs(x2-lx2)+Math.abs(y2-ly2)); + } + int bottomFit(double x1, double x2, double y1, double y2) { + return (int)(Math.abs(x1-lx1)+Math.abs(y2-ly1)+Math.abs(x2-lx2)+Math.abs(y2-ly2)); + } + } + + private void fitLinesToCells() { + List lines = new ArrayList(); + for (HSLFShape h : getShapes()) { + if (h instanceof HSLFLine) { + lines.add(new LineRect((HSLFLine)h)); } } - cells = new HSLFTableCell[lst.size()][maxrowlen]; - for (int i = 0; i < lst.size(); i++) { - row = lst.get(i); - for (int j = 0; j < row.size(); j++) { - HSLFTextShape tx = (HSLFTextShape)row.get(j); - cells[i][j] = new HSLFTableCell(tx.getSpContainer(), getParent()); - cells[i][j].setSheet(tx.getSheet()); + + final int threshold = 5; + + // TODO: this only works for non-rotated tables + for (HSLFTableCell[] tca : cells) { + for (HSLFTableCell tc : tca) { + final Rectangle cellAnchor = tc.getAnchor(); + + /** + * x1/y1 --------+ + * | | + * +---------x2/y2 + */ + final double x1 = cellAnchor.getMinX(); + final double x2 = cellAnchor.getMaxX(); + final double y1 = cellAnchor.getMinY(); + final double y2 = cellAnchor.getMaxY(); + + LineRect lline = null, tline = null, rline = null, bline = null; + int lfit = Integer.MAX_VALUE, tfit = Integer.MAX_VALUE, rfit = Integer.MAX_VALUE, bfit = Integer.MAX_VALUE; + + for (LineRect lr : lines) { + // calculate border fit + int lfitx = lr.leftFit(x1, x2, y1, y2); + if (lfitx < lfit) { + lfit = lfitx; + lline = lr; + } + + int tfitx = lr.topFit(x1, x2, y1, y2); + if (tfitx < tfit) { + tfit = tfitx; + tline = lr; + } + + int rfitx = lr.rightFit(x1, x2, y1, y2); + if (rfitx < rfit) { + rfit = rfitx; + rline = lr; + } + + int bfitx = lr.bottomFit(x1, x2, y1, y2); + if (bfitx < bfit) { + bfit = bfitx; + bline = lr; + } + } + + if (lfit < threshold) { + tc.borderLeft = lline.l; + } + if (tfit < threshold) { + tc.borderTop = tline.l; + } + if (rfit < threshold) { + tc.borderRight = rline.l; + } + if (bfit < threshold) { + tc.borderBottom = bline.l; + } } } } + protected void initTable(){ + cellListToArray(); + fitLinesToCells(); + } + /** * Assign the SlideShow this shape belongs to * @@ -232,151 +310,102 @@ implements HSLFShapeContainer, TableShape { */ public void setSheet(HSLFSheet sheet){ super.setSheet(sheet); - if(cells == null) initTable(); + if (cells == null) { + initTable(); + } else { + for (HSLFTableCell cols[] : cells) { + for (HSLFTableCell col : cols) { + col.setSheet(sheet); + } + } + } } - /** - * Sets the row height. - * - * @param row the row index (0-based) - * @param height the height to set (in pixels) - */ - public void setRowHeight(int row, int height){ + @Override + public void setRowHeight(int row, double height) { + int pxHeight = Units.pointsToPixel(height); int currentHeight = cells[row][0].getAnchor().height; - int dy = height - currentHeight; + int dy = pxHeight - currentHeight; for (int i = row; i < cells.length; i++) { for (int j = 0; j < cells[i].length; j++) { Rectangle anchor = cells[i][j].getAnchor(); - if(i == row) anchor.height = height; - else anchor.y += dy; + if(i == row) { + anchor.height = pxHeight; + } else { + anchor.y += dy; + } cells[i][j].setAnchor(anchor); } } Rectangle tblanchor = getAnchor(); tblanchor.height += dy; - setAnchor(tblanchor); + setExteriorAnchor(tblanchor); } - /** - * Sets the column width. - * - * @param col the column index (0-based) - * @param width the width to set (in pixels) - */ - public void setColumnWidth(int col, int width){ - int currentWidth = cells[0][col].getAnchor().width; - int dx = width - currentWidth; - for (int i = 0; i < cells.length; i++) { - Rectangle anchor = cells[i][col].getAnchor(); - anchor.width = width; - cells[i][col].setAnchor(anchor); - - if(col < cells[i].length - 1) for (int j = col+1; j < cells[i].length; j++) { - anchor = cells[i][j].getAnchor(); - anchor.x += dx; - cells[i][j].setAnchor(anchor); + @Override + public void setColumnWidth(int col, final double width){ + if (col < 0 || col >= cells[0].length) { + throw new IllegalArgumentException("Column index '"+col+"' is not within range [0-"+(cells[0].length-1)+"]"); + } + double currentWidth = cells[0][col].getAnchor().getWidth(); + double dx = width - currentWidth; + for (HSLFTableCell cols[] : cells) { + Rectangle anchor = cols[col].getAnchor(); + anchor.width = (int)Math.rint(width); + cols[col].setAnchor(anchor); + + if (col < cols.length - 1) { + for (int j = col+1; j < cols.length; j++) { + anchor = cols[j].getAnchor(); + anchor.x += dx; + cols[j].setAnchor(anchor); + } } } Rectangle tblanchor = getAnchor(); tblanchor.width += dx; - setAnchor(tblanchor); + setExteriorAnchor(tblanchor); } - /** - * Format the table and apply the specified Line to all cell boundaries, - * both outside and inside - * - * @param line the border line - */ - public void setAllBorders(HSLFLine line){ - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - HSLFTableCell cell = cells[i][j]; - cell.setBorderTop(cloneBorder(line)); - cell.setBorderLeft(cloneBorder(line)); - if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line)); - if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line)); - } - } - } - - /** - * Format the outside border using the specified Line object - * - * @param line the border line - */ - public void setOutsideBorders(HSLFLine line){ - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - HSLFTableCell cell = cells[i][j]; - - if(j == 0) cell.setBorderLeft(cloneBorder(line)); - if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line)); - else { - cell.setBorderLeft(null); - cell.setBorderLeft(null); - } - - if(i == 0) cell.setBorderTop(cloneBorder(line)); - else if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line)); - else { - cell.setBorderTop(null); - cell.setBorderBottom(null); + protected HSLFTableCell getRelativeCell(HSLFTableCell origin, int row, int col) { + int thisRow = 0, thisCol = 0; + boolean found = false; + outer: for (HSLFTableCell[] tca : cells) { + thisCol = 0; + for (HSLFTableCell tc : tca) { + if (tc == origin) { + found = true; + break outer; } + thisCol++; } + thisRow++; } - } - - /** - * Format the inside border using the specified Line object - * - * @param line the border line - */ - public void setInsideBorders(HSLFLine line){ - for (int i = 0; i < cells.length; i++) { - for (int j = 0; j < cells[i].length; j++) { - HSLFTableCell cell = cells[i][j]; - if(j != cells[i].length - 1) - cell.setBorderRight(cloneBorder(line)); - else { - cell.setBorderLeft(null); - cell.setBorderLeft(null); - } - if(i != cells.length - 1) cell.setBorderBottom(cloneBorder(line)); - else { - cell.setBorderTop(null); - cell.setBorderBottom(null); - } - } - } + int otherRow = thisRow + row; + int otherCol = thisCol + col; + return (found + && 0 <= otherRow && otherRow < cells.length + && 0 <= otherCol && otherCol < cells[otherRow].length) + ? cells[otherRow][otherCol] : null; } - private HSLFLine cloneBorder(HSLFLine line){ - HSLFLine border = createBorder(); - border.setLineWidth(line.getLineWidth()); - border.setLineDashing(line.getLineDashing()); - border.setLineColor(line.getLineColor()); - border.setLineCompound(line.getLineCompound()); - return border; + @Override + protected void moveAndScale(Rectangle anchorDest){ + super.moveAndScale(anchorDest); + updateRowHeightsProperty(); } - /** - * Create a border to format this table - * - * @return the created border - */ - public HSLFLine createBorder(){ - HSLFLine line = new HSLFLine(this); - + private void updateRowHeightsProperty() { AbstractEscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, -1); - setEscherProperty(opt, EscherProperties.GEOMETRY__FILLOK, -1); - setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000); - setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000); - - return line; + EscherArrayProperty p = opt.lookup(EscherProperties.GROUPSHAPE__TABLEROWPROPERTIES); + byte[] val = new byte[4]; + for (int rowIdx = 0; rowIdx < cells.length; rowIdx++) { + int rowHeight = Units.pointsToMaster(cells[rowIdx][0].getAnchor().height); + LittleEndian.putInt(val, 0, rowHeight); + p.setElement(rowIdx, val); + } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java index e3737e5e18..80341aa354 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java @@ -17,13 +17,18 @@ package org.apache.poi.hslf.usermodel; +import java.awt.Color; import java.awt.Rectangle; import org.apache.poi.ddf.AbstractEscherOptRecord; import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.draw.DrawPaint; +import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.sl.usermodel.StrokeStyle; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.sl.usermodel.TableCell; /** @@ -35,10 +40,10 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell parent){ + protected HSLFTableCell(EscherContainerRecord escherRecord, HSLFTable parent){ super(escherRecord, parent); } @@ -56,7 +61,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell parent){ + public HSLFTableCell(HSLFTable parent){ super(parent); setShapeType(ShapeType.RECT); @@ -76,82 +81,320 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell getTextRuns() { return _runs; } @@ -193,7 +190,7 @@ public final class HSLFTextParagraph implements TextParagraph iterator() { return _runs.iterator(); @@ -342,13 +339,13 @@ public final class HSLFTextParagraph implements TextParagraph paragraphs) { @@ -710,7 +707,7 @@ public final class HSLFTextParagraph implements TextParagraph paragraphs, String text, boolean newParagraph) { @@ -889,9 +886,13 @@ public final class HSLFTextParagraph implements TextParagraph 0) { + if (!lastRunEmpty) { + TextPropCollection tpc = htr.getCharacterStyle(); htr = new HSLFTextRun(htp); htr.getCharacterStyle().copy(tpc); htp.addTextRun(htr); @@ -921,7 +921,7 @@ public final class HSLFTextParagraph implements TextParagraph paragraphs, String text) { @@ -980,7 +980,7 @@ public final class HSLFTextParagraph implements TextParagraph findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) { @@ -1103,7 +1103,7 @@ public final class HSLFTextParagraph implements TextParagraph> findTextParagraphs(Record[] records) { @@ -1272,7 +1272,7 @@ public final class HSLFTextParagraph implements TextParagraph createEmptyParagraph(EscherTextboxWrapper wrapper) { TextHeaderAtom tha = new TextHeaderAtom(); tha.setParentRecord(wrapper); @@ -1301,10 +1301,10 @@ public final class HSLFTextParagraph implements TextParagraph>> 24; - Color tmp; + Color tmp; switch (cidx) { // Background ... Accent 3 color case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: @@ -1333,15 +1333,15 @@ public final class HSLFTextParagraph implements TextParagraph 0; } public byte getPitchAndFamily() { diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java index 1b5bbb83fd..f24173e204 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java @@ -17,20 +17,37 @@ package org.apache.poi.hslf.usermodel; -import static org.apache.poi.hslf.record.RecordTypes.*; +import static org.apache.poi.hslf.record.RecordTypes.OEPlaceholderAtom; +import static org.apache.poi.hslf.record.RecordTypes.RoundTripHFPlaceholder12; import java.awt.Rectangle; import java.awt.font.FontRenderContext; import java.awt.geom.Rectangle2D; import java.io.IOException; -import java.util.*; - -import org.apache.poi.ddf.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.ddf.AbstractEscherOptRecord; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.ddf.EscherSimpleProperty; +import org.apache.poi.ddf.EscherTextboxRecord; import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.record.EscherTextboxWrapper; +import org.apache.poi.hslf.record.InteractiveInfo; +import org.apache.poi.hslf.record.InteractiveInfoAtom; +import org.apache.poi.hslf.record.OEPlaceholderAtom; +import org.apache.poi.hslf.record.PPDrawing; +import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; +import org.apache.poi.hslf.record.TextHeaderAtom; +import org.apache.poi.hslf.record.TxInteractiveInfoAtom; import org.apache.poi.sl.draw.DrawFactory; import org.apache.poi.sl.draw.DrawTextShape; -import org.apache.poi.sl.usermodel.*; +import org.apache.poi.sl.usermodel.Insets2D; +import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.usermodel.TextShape; +import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.util.POILogger; import org.apache.poi.util.Units; @@ -57,14 +74,35 @@ implements TextShape { /* package */ static final int AnchorBottomCenteredBaseline = 9; /** - * How to wrap the text + * Specifies that a line of text will continue on subsequent lines instead + * of extending into or beyond a margin. + * Office Excel 2007, Excel 2010, PowerPoint 97, and PowerPoint 2010 read + * and use this value properly but do not write it. */ public static final int WrapSquare = 0; + /** + * Specifies a wrapping rule that is equivalent to that of WrapSquare + * Excel 97, Excel 2000, Excel 2002, and Office Excel 2003 use this value. + * All other product versions listed at the beginning of this appendix ignore this value. + */ public static final int WrapByPoints = 1; + /** + * Specifies that a line of text will extend into or beyond a margin instead + * of continuing on subsequent lines. + * Excel 97, Word 97, Excel 2000, Word 2000, Excel 2002, + * and Office Excel 2003 do not use this value. + */ public static final int WrapNone = 2; + /** + * Specifies a wrapping rule that is undefined and MUST be ignored. + */ public static final int WrapTopBottom = 3; + /** + * Specifies a wrapping rule that is undefined and MUST be ignored. + */ public static final int WrapThrough = 4; + /** * TextRun object which holds actual text and format data */ @@ -302,24 +340,6 @@ implements TextShape { setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align2); } - @Override - public VerticalAlignment getVerticalAlignment() { - int va = getAlignment(); - switch (va) { - case AnchorTop: - case AnchorTopCentered: - case AnchorTopBaseline: - case AnchorTopCenteredBaseline: return VerticalAlignment.TOP; - case AnchorBottom: - case AnchorBottomCentered: - case AnchorBottomBaseline: - case AnchorBottomCenteredBaseline: return VerticalAlignment.BOTTOM; - default: - case AnchorMiddle: - case AnchorMiddleCentered: return VerticalAlignment.MIDDLE; - } - } - /** * @return true, if vertical alignment is relative to baseline * this is only used for older versions less equals Office 2003 @@ -353,21 +373,33 @@ implements TextShape { return false; } } + + @Override + public void setHorizontalCentered(Boolean isCentered) { + setAlignment(isCentered, getVerticalAlignment()); + } - public void setVerticalAlignment(VerticalAlignment vAlign) { - setAlignment(isHorizontalCentered(), vAlign); + @Override + public VerticalAlignment getVerticalAlignment() { + int va = getAlignment(); + switch (va) { + case AnchorTop: + case AnchorTopCentered: + case AnchorTopBaseline: + case AnchorTopCenteredBaseline: return VerticalAlignment.TOP; + case AnchorBottom: + case AnchorBottomCentered: + case AnchorBottomBaseline: + case AnchorBottomCenteredBaseline: return VerticalAlignment.BOTTOM; + default: + case AnchorMiddle: + case AnchorMiddleCentered: return VerticalAlignment.MIDDLE; + } } - /** - * Sets if the paragraphs are horizontal centered - * - * @param isCentered true, if the paragraphs are horizontal centered - * A {@code null} values unsets this property. - * - * @see TextShape#isHorizontalCentered() - */ - public void setHorizontalCentered(Boolean isCentered){ - setAlignment(isCentered, getVerticalAlignment()); + @Override + public void setVerticalAlignment(VerticalAlignment vAlign) { + setAlignment(isHorizontalCentered(), vAlign); } /** @@ -479,12 +511,6 @@ implements TextShape { setEscherProperty(propId, Units.toEMU(margin)); } - @Override - public boolean getWordWrap(){ - int ww = getWordWrapEx(); - return (ww != WrapNone); - } - /** * Returns the value indicating word wrap. * @@ -498,17 +524,28 @@ implements TextShape { EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT); return prop == null ? WrapSquare : prop.getPropertyValue(); } - + /** * Specifies how the text should be wrapped * * @param wrap the value indicating how the text should be wrapped. * Must be one of the Wrap* constants defined in this class. */ - public void setWordWrap(int wrap){ + public void setWordWrapEx(int wrap){ setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap); } + @Override + public boolean getWordWrap(){ + int ww = getWordWrapEx(); + return (ww != WrapNone); + } + + @Override + public void setWordWrap(boolean wrap) { + setWordWrapEx(wrap ? WrapSquare : WrapNone); + } + /** * @return id for the text. */ @@ -699,6 +736,14 @@ implements TextShape { return insets; } + @Override + public void setInsets(Insets2D insets) { + setTopInset(insets.top); + setLeftInset(insets.left); + setBottomInset(insets.bottom); + setRightInset(insets.right); + } + @Override public double getTextHeight(){ DrawFactory drawFact = DrawFactory.getInstance(null); @@ -747,14 +792,7 @@ implements TextShape { return HSLFTextParagraph.appendText(paras, text, newParagraph); } - /** - * Sets (overwrites) the current text. - * Uses the properties of the first paragraph / textrun - * - * @param text the text string used by this object. - * - * @return the last text run of the splitted text - */ + @Override public HSLFTextRun setText(String text) { // init paragraphs List paras = getTextParagraphs(); @@ -783,5 +821,64 @@ implements TextShape { return HSLFHyperlink.find(this); } + @Override + public void setTextPlaceholder(TextPlaceholder placeholder) { + // TOOD: check for correct placeholder handling - see org.apache.poi.hslf.model.Placeholder + Placeholder ph = null; + int runType; + switch (placeholder) { + default: + case BODY: + runType = TextHeaderAtom.BODY_TYPE; + ph = Placeholder.BODY; + break; + case TITLE: + runType = TextHeaderAtom.TITLE_TYPE; + ph = Placeholder.TITLE; + break; + case CENTER_BODY: + runType = TextHeaderAtom.CENTRE_BODY_TYPE; + ph = Placeholder.BODY; + break; + case CENTER_TITLE: + runType = TextHeaderAtom.CENTER_TITLE_TYPE; + ph = Placeholder.TITLE; + break; + case HALF_BODY: + runType = TextHeaderAtom.HALF_BODY_TYPE; + ph = Placeholder.BODY; + break; + case QUARTER_BODY: + runType = TextHeaderAtom.QUARTER_BODY_TYPE; + ph = Placeholder.BODY; + break; + case NOTES: + runType = TextHeaderAtom.NOTES_TYPE; + break; + case OTHER: + runType = TextHeaderAtom.OTHER_TYPE; + break; + } + setRunType(runType); + if (ph != null) { + setPlaceholder(ph); + } + } + @Override + public TextPlaceholder getTextPlaceholder() { + switch (getRunType()) { + default: + case TextHeaderAtom.BODY_TYPE: return TextPlaceholder.BODY; + case TextHeaderAtom.TITLE_TYPE: return TextPlaceholder.TITLE; + case TextHeaderAtom.NOTES_TYPE: return TextPlaceholder.NOTES; + case TextHeaderAtom.OTHER_TYPE: return TextPlaceholder.OTHER; + case TextHeaderAtom.CENTRE_BODY_TYPE: return TextPlaceholder.CENTER_BODY; + case TextHeaderAtom.CENTER_TITLE_TYPE: return TextPlaceholder.CENTER_TITLE; + case TextHeaderAtom.HALF_BODY_TYPE: return TextPlaceholder.HALF_BODY; + case TextHeaderAtom.QUARTER_BODY_TYPE: return TextPlaceholder.QUARTER_BODY; + } + } + + } \ No newline at end of file diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java index b26e10215f..c601ca04b7 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java @@ -81,27 +81,27 @@ public final class TestLine { */ line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(450, 200, 300, 0)); - line.setLineDashing(LineDash.SOLID); + line.setLineDash(LineDash.SOLID); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(450, 230, 300, 0)); - line.setLineDashing(LineDash.DASH); + line.setLineDash(LineDash.DASH); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(450, 260, 300, 0)); - line.setLineDashing(LineDash.DOT); + line.setLineDash(LineDash.DOT); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(450, 290, 300, 0)); - line.setLineDashing(LineDash.DASH_DOT); + line.setLineDash(LineDash.DASH_DOT); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(450, 320, 300, 0)); - line.setLineDashing(LineDash.LG_DASH_DOT_DOT); + line.setLineDash(LineDash.LG_DASH_DOT_DOT); slide.addShape(line); /** @@ -109,21 +109,21 @@ public final class TestLine { */ line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(75, 400, 300, 0)); - line.setLineDashing(LineDash.DASH_DOT); + line.setLineDash(LineDash.DASH_DOT); line.setLineCompound(LineCompound.TRIPLE); line.setLineWidth(5.0); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(75, 430, 300, 0)); - line.setLineDashing(LineDash.DASH); + line.setLineDash(LineDash.DASH); line.setLineCompound(LineCompound.THICK_THIN); line.setLineWidth(4.0); slide.addShape(line); line = new HSLFLine(); line.setAnchor(new java.awt.Rectangle(75, 460, 300, 0)); - line.setLineDashing(LineDash.DOT); + line.setLineDash(LineDash.DOT); line.setLineCompound(LineCompound.DOUBLE); line.setLineWidth(8.0); slide.addShape(line); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java index f7fe4c43f4..3ce7a71b99 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java @@ -91,7 +91,7 @@ public final class TestShapes { java.awt.Rectangle lineAnchor = new java.awt.Rectangle(100, 200, 50, 60); line.setAnchor(lineAnchor); line.setLineWidth(3); - line.setLineDashing(LineDash.DASH); + line.setLineDash(LineDash.DASH); line.setLineColor(Color.red); slide.addShape(line); @@ -99,7 +99,7 @@ public final class TestShapes { java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111); ellipse.setAnchor(ellipseAnchor); ellipse.setLineWidth(2); - ellipse.setLineDashing(LineDash.SOLID); + ellipse.setLineDash(LineDash.SOLID); ellipse.setLineColor(Color.green); ellipse.setFillColor(Color.lightGray); slide.addShape(ellipse); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java index 8032d2da3e..9b11555b1a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java @@ -57,15 +57,15 @@ public final class TestTable { HSLFSlide slide = ppt.createSlide(); - HSLFTable tbl = new HSLFTable(2, 5); - slide.addShape(tbl); + HSLFTable tbl = slide.createTable(2, 5); HSLFTableCell cell = tbl.getCell(0, 0); //table cells have type=TextHeaderAtom.OTHER_TYPE, see bug #46033 assertEquals(TextHeaderAtom.OTHER_TYPE, cell.getTextParagraphs().get(0).getRunType()); - assertTrue(slide.getShapes().get(0) instanceof HSLFTable); - HSLFTable tbl2 = (HSLFTable)slide.getShapes().get(0); + HSLFShape tblSh = slide.getShapes().get(0); + assertTrue(tblSh instanceof HSLFTable); + HSLFTable tbl2 = (HSLFTable)tblSh; assertEquals(tbl.getNumberOfColumns(), tbl2.getNumberOfColumns()); assertEquals(tbl.getNumberOfRows(), tbl2.getNumberOfRows()); @@ -89,10 +89,9 @@ public final class TestTable { HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide slide = ppt.createSlide(); List shapes; - HSLFTable tbl1 = new HSLFTable(1, 5); + HSLFTable tbl1 = slide.createTable(1, 5); assertEquals(5, tbl1.getNumberOfColumns()); assertEquals(1, tbl1.getNumberOfRows()); - slide.addShape(tbl1); shapes = slide.getShapes(); assertEquals(1, shapes.size()); @@ -106,14 +105,16 @@ public final class TestTable { @Test public void testIllegalCOnstruction(){ + HSLFSlideShow ppt = new HSLFSlideShow(); + HSLFSlide slide = ppt.createSlide(); try { - new HSLFTable(0, 5); + slide.createTable(0, 5); fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); } catch (IllegalArgumentException e){ } try { - new HSLFTable(5, 0); + slide.createTable(5, 0); fail("Table(rownum, colnum) must throw IllegalArgumentException if any of tghe arguments is less than 1"); } catch (IllegalArgumentException e){ diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java index 2270cd420f..d32114a7f8 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java @@ -19,22 +19,49 @@ package org.apache.poi.hslf.usermodel; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.awt.Color; +import java.awt.Rectangle; import java.util.List; import org.apache.poi.POIDataSamples; +import org.apache.poi.sl.draw.DrawTableShape; +import org.apache.poi.sl.usermodel.StrokeStyle; import org.junit.Test; /** - * Test that checks numbered list functionality. - * - * @author Alex Nikiforov [mailto:anikif@gmail.com] + * Table related tests */ public class TestTable { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); + @Test + public void moveTable() throws Exception { + HSLFSlideShow ppt = new HSLFSlideShow(); + HSLFSlide slide = ppt.createSlide(); + int rows = 3, cols = 5; + HSLFTable table = slide.createTable(rows, cols); + for (int row=0; row