]> source.dussan.org Git - poi.git/commitdiff
Common sl unification - copy first paragraph / textrun properties on XSLFTextShape...
authorAndreas Beeker <kiwiwings@apache.org>
Thu, 29 Oct 2015 01:05:27 +0000 (01:05 +0000)
committerAndreas Beeker <kiwiwings@apache.org>
Thu, 29 Oct 2015 01:05:27 +0000 (01:05 +0000)
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

57 files changed:
src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java
src/examples/src/org/apache/poi/hslf/examples/TableDemo.java
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial3.java
src/examples/src/org/apache/poi/xslf/usermodel/Tutorial4.java
src/java/org/apache/poi/sl/draw/DrawTableShape.java
src/java/org/apache/poi/sl/draw/SLGraphics.java [new file with mode: 0644]
src/java/org/apache/poi/sl/usermodel/SimpleShape.java
src/java/org/apache/poi/sl/usermodel/SlideShow.java
src/java/org/apache/poi/sl/usermodel/StrokeStyle.java
src/java/org/apache/poi/sl/usermodel/TableCell.java
src/java/org/apache/poi/sl/usermodel/TableShape.java
src/java/org/apache/poi/sl/usermodel/TextBox.java
src/java/org/apache/poi/sl/usermodel/TextParagraph.java
src/java/org/apache/poi/sl/usermodel/TextRun.java
src/java/org/apache/poi/sl/usermodel/TextShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/Placeholder.java [deleted file]
src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFAutoShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSimpleShape.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideLayout.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlideMaster.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTable.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTableCell.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextBox.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java
src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFAutoShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFNotes.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java
src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java
src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java
src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java [deleted file]
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPlaceholder.java [new file with mode: 0644]
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTable.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTableCell.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java
src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java
src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTable.java
src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestTextRun.java

index c9114247263b0e9b342f295851b11afd9f8fbec6..8101c71f63009dba962e182680afe45ab97534d0 100644 (file)
@@ -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<HSLFTextParagraph> tp = box2.getTextParagraphs();
+        List<? extends TextParagraph<?,?,?>> 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<HSLFTextParagraph> tp = box2.getTextParagraphs();
+        List<? extends TextParagraph<?,?,?>> 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);
     }
 }
index d50855e6194be3e800187b9bdd6928d2f2dd1760..c8a139590234807167d713cd254652946accaeeb 100644 (file)
@@ -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");
index 54347b4c321cc8a6d59641ecd4a7e1cfeb6f5083..28c1fa3f1202331787cfa15ac0cc6d7a9912fb2f 100644 (file)
@@ -23,6 +23,8 @@ import java.awt.Rectangle;
 import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 \r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
+\r
 /**\r
  * How to set slide title\r
  *\r
index ecfc986670493e2b3e109b5ca194bc6078d190cd..94082a2ef967bbaf072e02e2ebc5a63e41a809ef 100644 (file)
@@ -24,6 +24,7 @@ import java.awt.Rectangle;
 import java.io.FileOutputStream;\r
 import java.io.IOException;\r
 \r
+import org.apache.poi.sl.usermodel.TableCell.BorderEdge;\r
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;\r
 \r
 /**\r
@@ -56,8 +57,8 @@ public class Tutorial4 {
             r.setBold(true);\r
             r.setFontColor(Color.white);\r
             th.setFillColor(new Color(79, 129, 189));\r
-            th.setBorderBottom(2);\r
-            th.setBorderBottomColor(Color.white);\r
+            th.setBorderWidth(BorderEdge.bottom, 2.0);\r
+            th.setBorderColor(BorderEdge.bottom, Color.white);\r
 \r
             tbl.setColumnWidth(i, 150);  // all columns are equally sized\r
         }\r
index b252ddfda934c03db7f5c10eae39b4b38f086df2..ec44d17d6ba7a2cbdaf03478a825f7719687dd64 100644 (file)
 \r
 package org.apache.poi.sl.draw;\r
 \r
+import java.awt.Color;\r
 import java.awt.Graphics2D;\r
 \r
 import org.apache.poi.sl.usermodel.GroupShape;\r
+import org.apache.poi.sl.usermodel.StrokeStyle;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
+import org.apache.poi.sl.usermodel.TableCell;\r
+import org.apache.poi.sl.usermodel.TableCell.BorderEdge;\r
 import org.apache.poi.sl.usermodel.TableShape;\r
 \r
 public class DrawTableShape extends DrawShape {\r
@@ -57,5 +63,111 @@ public class DrawTableShape extends DrawShape {
         }\r
     }\r
 \r
+    @Override\r
+    protected TableShape<?,?> getShape() {\r
+        return (TableShape<?,?>)shape;\r
+    }    \r
+    \r
+    /**\r
+     * Format the table and apply the specified Line to all cell boundaries,\r
+     * both outside and inside.\r
+     * An empty args parameter removes the affected border.\r
+     *\r
+     * @param args a varargs array possible containing {@link Double} (width),\r
+     * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash}\r
+     */\r
+    public void setAllBorders(Object... args) {\r
+        TableShape<?,?> table = getShape();\r
+        final int rows = table.getNumberOfRows();\r
+        final int cols = table.getNumberOfColumns();\r
+        \r
+        BorderEdge edges[] = { BorderEdge.top, BorderEdge.left, null, null };\r
+        for (int row = 0; row < rows; row++) {\r
+            for (int col = 0; col < cols; col++) {\r
+                edges[2] = (col == cols - 1) ? BorderEdge.right : null;\r
+                edges[3] = (row == rows - 1) ? BorderEdge.bottom : null;\r
+                setEdges(table.getCell(row, col), edges, args);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Format the outside border using the specified Line object\r
+     * An empty args parameter removes the affected border.\r
+     *\r
+     * @param args a varargs array possible containing {@link Double} (width),\r
+     * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash}\r
+     */\r
+    public void setOutsideBorders(Object... args){\r
+        if (args.length == 0) return;\r
+        \r
+        TableShape<?,?> table = getShape();\r
+        final int rows = table.getNumberOfRows();\r
+        final int cols = table.getNumberOfColumns();\r
+        \r
+        BorderEdge edges[] = new BorderEdge[4];\r
+        for (int row = 0; row < rows; row++) {\r
+            for (int col = 0; col < cols; col++) {\r
+                edges[0] = (col == 0) ? BorderEdge.left : null;\r
+                edges[1] = (col == cols - 1) ? BorderEdge.right : null;\r
+                edges[2] = (row == 0) ? BorderEdge.top : null;\r
+                edges[3] = (row == rows - 1) ? BorderEdge.bottom : null;\r
+                setEdges(table.getCell(row, col), edges, args);\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Format the inside border using the specified Line object\r
+     * An empty args parameter removes the affected border.\r
+     *\r
+     * @param args a varargs array possible containing {@link Double} (width),\r
+     * {@link StrokeStyle.LineCompound}, {@link Color}, {@link StrokeStyle.LineDash}\r
+     */\r
+    public void setInsideBorders(Object... args) {\r
+        if (args.length == 0) return;\r
+        \r
+        TableShape<?,?> table = getShape();\r
+        final int rows = table.getNumberOfRows();\r
+        final int cols = table.getNumberOfColumns();\r
+        \r
+        BorderEdge edges[] = new BorderEdge[2];\r
+        for (int row = 0; row < rows; row++) {\r
+            for (int col = 0; col < cols; col++) {\r
+                edges[0] = (col > 0 && col < cols - 1) ? BorderEdge.right : null;\r
+                edges[1] = (row > 0 && row < rows - 1) ? BorderEdge.bottom : null;\r
+                setEdges(table.getCell(row, col), edges, args);\r
+            }\r
+        }\r
+    }\r
+    \r
+    /**\r
+     * Apply the border attributes (args) to the given cell and edges\r
+     *\r
+     * @param cell the cell\r
+     * @param edges the border edges\r
+     * @param args the border attributes\r
+     */\r
+    private static void setEdges(TableCell<?,?> cell, BorderEdge edges[], Object... args) {\r
+        for (BorderEdge be : edges) {\r
+            if (be != null) {\r
+                if (args.length == 0) {\r
+                    cell.removeBorder(be);\r
+                } else {\r
+                    for (Object o : args) {\r
+                        if (o instanceof Double) {\r
+                            cell.setBorderWidth(be, (Double)o);\r
+                        } else if (o instanceof Color) {\r
+                            cell.setBorderColor(be, (Color)o);\r
+                        } else if (o instanceof LineDash) {\r
+                            cell.setBorderDash(be, (LineDash)o);\r
+                        } else if (o instanceof LineCompound) {\r
+                            cell.setBorderCompound(be, (LineCompound)o);\r
+                        }\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
     \r
 }\r
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 (file)
index 0000000..2a6d884
--- /dev/null
@@ -0,0 +1,1831 @@
+/* ====================================================================\r
+   Licensed to the Apache Software Foundation (ASF) under one or more\r
+   contributor license agreements.  See the NOTICE file distributed with\r
+   this work for additional information regarding copyright ownership.\r
+   The ASF licenses this file to You under the Apache License, Version 2.0\r
+   (the "License"); you may not use this file except in compliance with\r
+   the License.  You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+==================================================================== */\r
+\r
+package org.apache.poi.sl.draw;\r
+\r
+\r
+import java.awt.BasicStroke;\r
+import java.awt.Color;\r
+import java.awt.Composite;\r
+import java.awt.Font;\r
+import java.awt.FontMetrics;\r
+import java.awt.Graphics;\r
+import java.awt.Graphics2D;\r
+import java.awt.GraphicsConfiguration;\r
+import java.awt.GraphicsEnvironment;\r
+import java.awt.Image;\r
+import java.awt.Paint;\r
+import java.awt.Rectangle;\r
+import java.awt.RenderingHints;\r
+import java.awt.Shape;\r
+import java.awt.Stroke;\r
+import java.awt.Toolkit;\r
+import java.awt.font.FontRenderContext;\r
+import java.awt.font.GlyphVector;\r
+import java.awt.font.TextLayout;\r
+import java.awt.geom.AffineTransform;\r
+import java.awt.geom.Arc2D;\r
+import java.awt.geom.Ellipse2D;\r
+import java.awt.geom.GeneralPath;\r
+import java.awt.geom.Line2D;\r
+import java.awt.geom.RoundRectangle2D;\r
+import java.awt.image.BufferedImage;\r
+import java.awt.image.BufferedImageOp;\r
+import java.awt.image.ImageObserver;\r
+import java.awt.image.RenderedImage;\r
+import java.awt.image.renderable.RenderableImage;\r
+import java.text.AttributedCharacterIterator;\r
+import java.util.Map;\r
+\r
+import org.apache.poi.sl.usermodel.FreeformShape;\r
+import org.apache.poi.sl.usermodel.GroupShape;\r
+import org.apache.poi.sl.usermodel.Insets2D;\r
+import org.apache.poi.sl.usermodel.SimpleShape;\r
+import org.apache.poi.sl.usermodel.StrokeStyle;\r
+import org.apache.poi.sl.usermodel.TextBox;\r
+import org.apache.poi.sl.usermodel.TextRun;\r
+import org.apache.poi.sl.usermodel.VerticalAlignment;\r
+import org.apache.poi.util.POILogFactory;\r
+import org.apache.poi.util.POILogger;\r
+import org.apache.poi.util.SuppressForbidden;\r
+\r
+/**\r
+ * Translates Graphics2D calls into PowerPoint.\r
+ *\r
+ * @author Yegor Kozlov\r
+ */\r
+public final class SLGraphics extends Graphics2D implements Cloneable {\r
+\r
+    protected POILogger log = POILogFactory.getLogger(this.getClass());\r
+\r
+    //The ppt object to write into.\r
+    private GroupShape<?,?> _group;\r
+\r
+    private AffineTransform _transform;\r
+    private Stroke _stroke;\r
+    private Paint _paint;\r
+    private Font _font;\r
+    private Color _foreground;\r
+    private Color _background;\r
+    private RenderingHints _hints;\r
+\r
+    /**\r
+     * Construct Java Graphics object which translates graphic calls in ppt drawing layer.\r
+     *\r
+     * @param group           The shape group to write the graphics calls into.\r
+     */\r
+    public SLGraphics(GroupShape<?,?> group){\r
+        this._group = group;\r
+\r
+        _transform = new AffineTransform();\r
+        _stroke = new BasicStroke();\r
+        _paint = Color.black;\r
+        _font = new Font("Arial", Font.PLAIN, 12);\r
+        _background = Color.black;\r
+        _foreground = Color.white;\r
+        _hints = new RenderingHints(null);\r
+    }\r
+\r
+    /**\r
+     * @return  the shape group being used for drawing\r
+     */\r
+    public GroupShape<?,?> getShapeGroup(){\r
+        return _group;\r
+    }\r
+\r
+    /**\r
+     * Gets the current font.\r
+     * @return    this graphics context's current font.\r
+     * @see       java.awt.Font\r
+     * @see       java.awt.Graphics#setFont(Font)\r
+     */\r
+    public Font getFont(){\r
+        return _font;\r
+    }\r
+\r
+    /**\r
+     * Sets this graphics context's font to the specified font.\r
+     * All subsequent text operations using this graphics context\r
+     * use this font.\r
+     * @param  font   the font.\r
+     * @see     java.awt.Graphics#getFont\r
+     * @see     java.awt.Graphics#drawString(java.lang.String, int, int)\r
+     * @see     java.awt.Graphics#drawBytes(byte[], int, int, int, int)\r
+     * @see     java.awt.Graphics#drawChars(char[], int, int, int, int)\r
+    */\r
+    public void setFont(Font font){\r
+        this._font = font;\r
+    }\r
+\r
+    /**\r
+     * Gets this graphics context's current color.\r
+     * @return    this graphics context's current color.\r
+     * @see       java.awt.Color\r
+     * @see       java.awt.Graphics#setColor\r
+     */\r
+     public Color getColor(){\r
+        return _foreground;\r
+    }\r
+\r
+    /**\r
+     * Sets this graphics context's current color to the specified\r
+     * color. All subsequent graphics operations using this graphics\r
+     * context use this specified color.\r
+     * @param     c   the new rendering color.\r
+     * @see       java.awt.Color\r
+     * @see       java.awt.Graphics#getColor\r
+     */\r
+    public void setColor(Color c) {\r
+        setPaint(c);\r
+    }\r
+\r
+    /**\r
+     * Returns the current <code>Stroke</code> in the\r
+     * <code>Graphics2D</code> context.\r
+     * @return the current <code>Graphics2D</code> <code>Stroke</code>,\r
+     *                 which defines the line style.\r
+     * @see #setStroke\r
+     */\r
+    public Stroke getStroke(){\r
+        return _stroke;\r
+    }\r
+\r
+    /**\r
+     * Sets the <code>Stroke</code> for the <code>Graphics2D</code> context.\r
+     * @param s the <code>Stroke</code> object to be used to stroke a\r
+     * <code>Shape</code> during the rendering process\r
+     */\r
+    public void setStroke(Stroke s){\r
+        this._stroke = s;\r
+    }\r
+\r
+    /**\r
+     * Returns the current <code>Paint</code> of the\r
+     * <code>Graphics2D</code> context.\r
+     * @return the current <code>Graphics2D</code> <code>Paint</code>,\r
+     * which defines a color or pattern.\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     */\r
+    public Paint getPaint(){\r
+        return _paint;\r
+    }\r
+\r
+    /**\r
+     * Sets the <code>Paint</code> attribute for the\r
+     * <code>Graphics2D</code> context.  Calling this method\r
+     * with a <code>null</code> <code>Paint</code> object does\r
+     * not have any effect on the current <code>Paint</code> attribute\r
+     * of this <code>Graphics2D</code>.\r
+     * @param paint the <code>Paint</code> object to be used to generate\r
+     * color during the rendering process, or <code>null</code>\r
+     * @see java.awt.Graphics#setColor\r
+     */\r
+     public void setPaint(Paint paint){\r
+        if(paint == null) return;\r
+\r
+        this._paint = paint;\r
+        if (paint instanceof Color) _foreground = (Color)paint;\r
+    }\r
+\r
+    /**\r
+     * Returns a copy of the current <code>Transform</code> in the\r
+     * <code>Graphics2D</code> context.\r
+     * @return the current <code>AffineTransform</code> in the\r
+     *             <code>Graphics2D</code> context.\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     */\r
+    public AffineTransform getTransform(){\r
+        return new AffineTransform(_transform);\r
+    }\r
+\r
+    /**\r
+     * Sets the <code>Transform</code> in the <code>Graphics2D</code>\r
+     * context.\r
+     * @param Tx the <code>AffineTransform</code> object to be used in the\r
+     * rendering process\r
+     * @see #_transform\r
+     * @see AffineTransform\r
+     */\r
+    public void setTransform(AffineTransform Tx) {\r
+        _transform = new AffineTransform(Tx);\r
+    }\r
+\r
+    /**\r
+     * Strokes the outline of a <code>Shape</code> using the settings of the\r
+     * current <code>Graphics2D</code> context.  The rendering attributes\r
+     * applied include the <code>Clip</code>, <code>Transform</code>,\r
+     * <code>Paint</code>, <code>Composite</code> and\r
+     * <code>Stroke</code> attributes.\r
+     * @param shape the <code>Shape</code> to be rendered\r
+     * @see #setStroke\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #clip\r
+     * @see #setClip\r
+     * @see #setComposite\r
+     */\r
+    public void draw(Shape shape){\r
+        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));\r
+        FreeformShape<?,?> p = _group.createFreeform();\r
+        p.setPath(path);\r
+        p.setFillColor(null);\r
+        applyStroke(p);\r
+        if (_paint instanceof Color) {\r
+            p.setStrokeStyle((Color)_paint);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Renders the text specified by the specified <code>String</code>,\r
+     * using the current text attribute state in the <code>Graphics2D</code> context.\r
+     * The baseline of the first character is at position\r
+     * (<i>x</i>,&nbsp;<i>y</i>) in the User Space.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, <code>Paint</code>, <code>Font</code> and\r
+     * <code>Composite</code> attributes. For characters in script systems\r
+     * such as Hebrew and Arabic, the glyphs can be rendered from right to\r
+     * left, in which case the coordinate supplied is the location of the\r
+     * leftmost character on the baseline.\r
+     * @param s the <code>String</code> to be rendered\r
+     * @param x the x coordinate of the location where the\r
+     * <code>String</code> should be rendered\r
+     * @param y the y coordinate of the location where the\r
+     * <code>String</code> should be rendered\r
+     * @throws NullPointerException if <code>str</code> is\r
+     *         <code>null</code>\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     * @see java.awt.Graphics#setFont\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #setClip\r
+     */\r
+    public void drawString(String s, float x, float y) {\r
+        TextBox<?,?> txt = _group.createTextBox();\r
+\r
+        TextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0);\r
+        rt.setFontSize((double)_font.getSize());\r
+        rt.setFontFamily(_font.getFamily());\r
+\r
+        if (getColor() != null) rt.setFontColor(DrawPaint.createSolidPaint(getColor()));\r
+        if (_font.isBold()) rt.setBold(true);\r
+        if (_font.isItalic()) rt.setItalic(true);\r
+\r
+        txt.setText(s);\r
+\r
+        txt.setInsets(new Insets2D(0,0,0,0));\r
+        txt.setWordWrap(false);\r
+        txt.setHorizontalCentered(false);\r
+        txt.setVerticalAlignment(VerticalAlignment.MIDDLE);\r
+\r
+\r
+        TextLayout layout = new TextLayout(s, _font, getFontRenderContext());\r
+        float ascent = layout.getAscent();\r
+\r
+        float width = (float) Math.floor(layout.getAdvance());\r
+        /**\r
+         * Even if top and bottom margins are set to 0 PowerPoint\r
+         * always sets extra space between the text and its bounding box.\r
+         *\r
+         * The approximation height = ascent*2 works good enough in most cases\r
+         */\r
+        float height = ascent * 2;\r
+\r
+        /*\r
+          In powerpoint anchor of a shape is its top left corner.\r
+          Java graphics sets string coordinates by the baseline of the first character\r
+          so we need to shift up by the height of the textbox\r
+        */\r
+        y -= height / 2 + ascent / 2;\r
+\r
+        /*\r
+          In powerpoint anchor of a shape is its top left corner.\r
+          Java graphics sets string coordinates by the baseline of the first character\r
+          so we need to shift down by the height of the textbox\r
+        */\r
+        txt.setAnchor(new Rectangle((int)x, (int)y, (int)width, (int)height));\r
+    }\r
+\r
+    /**\r
+     * Fills the interior of a <code>Shape</code> using the settings of the\r
+     * <code>Graphics2D</code> context. The rendering attributes applied\r
+     * include the <code>Clip</code>, <code>Transform</code>,\r
+     * <code>Paint</code>, and <code>Composite</code>.\r
+     * @param shape the <code>Shape</code> to be filled\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #clip\r
+     * @see #setClip\r
+     */\r
+    public void fill(Shape shape){\r
+        GeneralPath path = new GeneralPath(_transform.createTransformedShape(shape));\r
+        FreeformShape<?,?> p = _group.createFreeform();\r
+        p.setPath(path);\r
+        applyPaint(p);\r
+        p.setStrokeStyle();   //Fills must be "No Line"\r
+    }\r
+\r
+    /**\r
+     * Translates the origin of the graphics context to the point\r
+     * (<i>x</i>,&nbsp;<i>y</i>) in the current coordinate system.\r
+     * Modifies this graphics context so that its new origin corresponds\r
+     * to the point (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's\r
+     * original coordinate system.  All coordinates used in subsequent\r
+     * rendering operations on this graphics context will be relative\r
+     * to this new origin.\r
+     * @param  x   the <i>x</i> coordinate.\r
+     * @param  y   the <i>y</i> coordinate.\r
+     */\r
+    public void translate(int x, int y){\r
+        _transform.translate(x, y);\r
+    }\r
+\r
+    /**\r
+     * Intersects the current <code>Clip</code> with the interior of the\r
+     * specified <code>Shape</code> and sets the <code>Clip</code> to the\r
+     * resulting intersection.  The specified <code>Shape</code> is\r
+     * transformed with the current <code>Graphics2D</code>\r
+     * <code>Transform</code> before being intersected with the current\r
+     * <code>Clip</code>.  This method is used to make the current\r
+     * <code>Clip</code> smaller.\r
+     * To make the <code>Clip</code> larger, use <code>setClip</code>.\r
+     * The <i>user clip</i> modified by this method is independent of the\r
+     * clipping associated with device bounds and visibility.  If no clip has\r
+     * previously been set, or if the clip has been cleared using\r
+     * {@link java.awt.Graphics#setClip(Shape) setClip} with a\r
+     * <code>null</code> argument, the specified <code>Shape</code> becomes\r
+     * the new user clip.\r
+     * @param s the <code>Shape</code> to be intersected with the current\r
+     *          <code>Clip</code>.  If <code>s</code> is <code>null</code>,\r
+     *          this method clears the current <code>Clip</code>.\r
+     */\r
+    public void clip(Shape s){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Gets the current clipping area.\r
+     * This method returns the user clip, which is independent of the\r
+     * clipping associated with device bounds and window visibility.\r
+     * If no clip has previously been set, or if the clip has been\r
+     * cleared using <code>setClip(null)</code>, this method returns\r
+     * <code>null</code>.\r
+     * @return      a <code>Shape</code> object representing the\r
+     *              current clipping area, or <code>null</code> if\r
+     *              no clip is set.\r
+     * @see         java.awt.Graphics#getClipBounds()\r
+     * @see         java.awt.Graphics#clipRect\r
+     * @see         java.awt.Graphics#setClip(int, int, int, int)\r
+     * @see         java.awt.Graphics#setClip(Shape)\r
+     * @since       JDK1.1\r
+     */\r
+    public Shape getClip(){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Concatenates the current <code>Graphics2D</code>\r
+     * <code>Transform</code> with a scaling transformation\r
+     * Subsequent rendering is resized according to the specified scaling\r
+     * factors relative to the previous scaling.\r
+     * This is equivalent to calling <code>transform(S)</code>, where S is an\r
+     * <code>AffineTransform</code> represented by the following matrix:\r
+     * <pre>\r
+     *          [   sx   0    0   ]\r
+     *          [   0    sy   0   ]\r
+     *          [   0    0    1   ]\r
+     * </pre>\r
+     * @param sx the amount by which X coordinates in subsequent\r
+     * rendering operations are multiplied relative to previous\r
+     * rendering operations.\r
+     * @param sy the amount by which Y coordinates in subsequent\r
+     * rendering operations are multiplied relative to previous\r
+     * rendering operations.\r
+     */\r
+    public void scale(double sx, double sy){\r
+        _transform.scale(sx, sy);\r
+    }\r
+\r
+    /**\r
+     * Draws an outlined round-cornered rectangle using this graphics\r
+     * context's current color. The left and right edges of the rectangle\r
+     * are at <code>x</code> and <code>x&nbsp;+&nbsp;width</code>,\r
+     * respectively. The top and bottom edges of the rectangle are at\r
+     * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>.\r
+     * @param      x the <i>x</i> coordinate of the rectangle to be drawn.\r
+     * @param      y the <i>y</i> coordinate of the rectangle to be drawn.\r
+     * @param      width the width of the rectangle to be drawn.\r
+     * @param      height the height of the rectangle to be drawn.\r
+     * @param      arcWidth the horizontal diameter of the arc\r
+     *                    at the four corners.\r
+     * @param      arcHeight the vertical diameter of the arc\r
+     *                    at the four corners.\r
+     * @see        java.awt.Graphics#fillRoundRect\r
+     */\r
+    public void drawRoundRect(int x, int y, int width, int height,\r
+                              int arcWidth, int arcHeight){\r
+        RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);\r
+        draw(rect);\r
+     }\r
+\r
+    /**\r
+     * Draws the text given by the specified string, using this\r
+     * graphics context's current font and color. The baseline of the\r
+     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this\r
+     * graphics context's coordinate system.\r
+     * @param       str      the string to be drawn.\r
+     * @param       x        the <i>x</i> coordinate.\r
+     * @param       y        the <i>y</i> coordinate.\r
+     * @see         java.awt.Graphics#drawBytes\r
+     * @see         java.awt.Graphics#drawChars\r
+     */\r
+    public void drawString(String str, int x, int y){\r
+        drawString(str, (float)x, (float)y);\r
+    }\r
+\r
+    /**\r
+     * Fills an oval bounded by the specified rectangle with the\r
+     * current color.\r
+     * @param       x the <i>x</i> coordinate of the upper left corner\r
+     *                     of the oval to be filled.\r
+     * @param       y the <i>y</i> coordinate of the upper left corner\r
+     *                     of the oval to be filled.\r
+     * @param       width the width of the oval to be filled.\r
+     * @param       height the height of the oval to be filled.\r
+     * @see         java.awt.Graphics#drawOval\r
+     */\r
+    public void fillOval(int x, int y, int width, int height){\r
+        Ellipse2D oval = new Ellipse2D.Float(x, y, width, height);\r
+        fill(oval);\r
+    }\r
+\r
+    /**\r
+     * Fills the specified rounded corner rectangle with the current color.\r
+     * The left and right edges of the rectangle\r
+     * are at <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>,\r
+     * respectively. The top and bottom edges of the rectangle are at\r
+     * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.\r
+     * @param       x the <i>x</i> coordinate of the rectangle to be filled.\r
+     * @param       y the <i>y</i> coordinate of the rectangle to be filled.\r
+     * @param       width the width of the rectangle to be filled.\r
+     * @param       height the height of the rectangle to be filled.\r
+     * @param       arcWidth the horizontal diameter\r
+     *                     of the arc at the four corners.\r
+     * @param       arcHeight the vertical diameter\r
+     *                     of the arc at the four corners.\r
+     * @see         java.awt.Graphics#drawRoundRect\r
+     */\r
+    public void fillRoundRect(int x, int y, int width, int height,\r
+                              int arcWidth, int arcHeight){\r
+\r
+        RoundRectangle2D rect = new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight);\r
+        fill(rect);\r
+    }\r
+\r
+    /**\r
+     * Fills a circular or elliptical arc covering the specified rectangle.\r
+     * <p>\r
+     * The resulting arc begins at <code>startAngle</code> and extends\r
+     * for <code>arcAngle</code> degrees.\r
+     * Angles are interpreted such that 0&nbsp;degrees\r
+     * is at the 3&nbsp;o'clock position.\r
+     * A positive value indicates a counter-clockwise rotation\r
+     * while a negative value indicates a clockwise rotation.\r
+     * <p>\r
+     * The center of the arc is the center of the rectangle whose origin\r
+     * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the\r
+     * <code>width</code> and <code>height</code> arguments.\r
+     * <p>\r
+     * The resulting arc covers an area\r
+     * <code>width&nbsp;+&nbsp;1</code> pixels wide\r
+     * by <code>height&nbsp;+&nbsp;1</code> pixels tall.\r
+     * <p>\r
+     * The angles are specified relative to the non-square extents of\r
+     * the bounding rectangle such that 45 degrees always falls on the\r
+     * line from the center of the ellipse to the upper right corner of\r
+     * the bounding rectangle. As a result, if the bounding rectangle is\r
+     * noticeably longer in one axis than the other, the angles to the\r
+     * start and end of the arc segment will be skewed farther along the\r
+     * longer axis of the bounds.\r
+     * @param        x the <i>x</i> coordinate of the\r
+     *                    upper-left corner of the arc to be filled.\r
+     * @param        y the <i>y</i>  coordinate of the\r
+     *                    upper-left corner of the arc to be filled.\r
+     * @param        width the width of the arc to be filled.\r
+     * @param        height the height of the arc to be filled.\r
+     * @param        startAngle the beginning angle.\r
+     * @param        arcAngle the angular extent of the arc,\r
+     *                    relative to the start angle.\r
+     * @see         java.awt.Graphics#drawArc\r
+     */\r
+    public void fillArc(int x, int y, int width, int height,\r
+                        int startAngle, int arcAngle){\r
+        Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.PIE);\r
+        fill(arc);\r
+    }\r
+\r
+    /**\r
+     * Draws the outline of a circular or elliptical arc\r
+     * covering the specified rectangle.\r
+     * <p>\r
+     * The resulting arc begins at <code>startAngle</code> and extends\r
+     * for <code>arcAngle</code> degrees, using the current color.\r
+     * Angles are interpreted such that 0&nbsp;degrees\r
+     * is at the 3&nbsp;o'clock position.\r
+     * A positive value indicates a counter-clockwise rotation\r
+     * while a negative value indicates a clockwise rotation.\r
+     * <p>\r
+     * The center of the arc is the center of the rectangle whose origin\r
+     * is (<i>x</i>,&nbsp;<i>y</i>) and whose size is specified by the\r
+     * <code>width</code> and <code>height</code> arguments.\r
+     * <p>\r
+     * The resulting arc covers an area\r
+     * <code>width&nbsp;+&nbsp;1</code> pixels wide\r
+     * by <code>height&nbsp;+&nbsp;1</code> pixels tall.\r
+     * <p>\r
+     * The angles are specified relative to the non-square extents of\r
+     * the bounding rectangle such that 45 degrees always falls on the\r
+     * line from the center of the ellipse to the upper right corner of\r
+     * the bounding rectangle. As a result, if the bounding rectangle is\r
+     * noticeably longer in one axis than the other, the angles to the\r
+     * start and end of the arc segment will be skewed farther along the\r
+     * longer axis of the bounds.\r
+     * @param        x the <i>x</i> coordinate of the\r
+     *                    upper-left corner of the arc to be drawn.\r
+     * @param        y the <i>y</i>  coordinate of the\r
+     *                    upper-left corner of the arc to be drawn.\r
+     * @param        width the width of the arc to be drawn.\r
+     * @param        height the height of the arc to be drawn.\r
+     * @param        startAngle the beginning angle.\r
+     * @param        arcAngle the angular extent of the arc,\r
+     *                    relative to the start angle.\r
+     * @see         java.awt.Graphics#fillArc\r
+     */\r
+    public void drawArc(int x, int y, int width, int height,\r
+                        int startAngle, int arcAngle) {\r
+        Arc2D arc = new Arc2D.Float(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN);\r
+        draw(arc);\r
+    }\r
+\r
+\r
+    /**\r
+     * Draws a sequence of connected lines defined by\r
+     * arrays of <i>x</i> and <i>y</i> coordinates.\r
+     * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.\r
+     * The figure is not closed if the first point\r
+     * differs from the last point.\r
+     * @param       xPoints an array of <i>x</i> points\r
+     * @param       yPoints an array of <i>y</i> points\r
+     * @param       nPoints the total number of points\r
+     * @see         java.awt.Graphics#drawPolygon(int[], int[], int)\r
+     * @since       JDK1.1\r
+     */\r
+    public void drawPolyline(int[] xPoints, int[] yPoints,\r
+                             int nPoints){\r
+        if(nPoints > 0){\r
+            GeneralPath path = new GeneralPath();\r
+            path.moveTo(xPoints[0], yPoints[0]);\r
+            for(int i=1; i<nPoints; i++)\r
+                path.lineTo(xPoints[i], yPoints[i]);\r
+\r
+            draw(path);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Draws the outline of an oval.\r
+     * The result is a circle or ellipse that fits within the\r
+     * rectangle specified by the <code>x</code>, <code>y</code>,\r
+     * <code>width</code>, and <code>height</code> arguments.\r
+     * <p>\r
+     * The oval covers an area that is\r
+     * <code>width&nbsp;+&nbsp;1</code> pixels wide\r
+     * and <code>height&nbsp;+&nbsp;1</code> pixels tall.\r
+     * @param       x the <i>x</i> coordinate of the upper left\r
+     *                     corner of the oval to be drawn.\r
+     * @param       y the <i>y</i> coordinate of the upper left\r
+     *                     corner of the oval to be drawn.\r
+     * @param       width the width of the oval to be drawn.\r
+     * @param       height the height of the oval to be drawn.\r
+     * @see         java.awt.Graphics#fillOval\r
+     */\r
+    public void drawOval(int x, int y, int width, int height){\r
+        Ellipse2D oval = new Ellipse2D.Float(x, y, width, height);\r
+        draw(oval);\r
+    }\r
+\r
+    /**\r
+     * Draws as much of the specified image as is currently available.\r
+     * The image is drawn with its top-left corner at\r
+     * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate\r
+     * space.  Transparent pixels are drawn in the specified\r
+     * background color.\r
+     * <p>\r
+     * This operation is equivalent to filling a rectangle of the\r
+     * width and height of the specified image with the given color and then\r
+     * drawing the image on top of it, but possibly more efficient.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * complete image has not yet been loaded, and it has not been dithered\r
+     * and converted for the current output device.\r
+     * <p>\r
+     * If the image has not yet been completely loaded, then\r
+     * <code>drawImage</code> returns <code>false</code>. As more of\r
+     * the image becomes available, the process that draws the image notifies\r
+     * the specified image observer.\r
+     * @param    img    the specified image to be drawn.\r
+     * @param    x      the <i>x</i> coordinate.\r
+     * @param    y      the <i>y</i> coordinate.\r
+     * @param    bgcolor the background color to paint under the\r
+     *                         non-opaque portions of the image.\r
+     * @param    observer    object to be notified as more of\r
+     *                          the image is converted.\r
+     * @see      java.awt.Image\r
+     * @see      java.awt.image.ImageObserver\r
+     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     */\r
+    public boolean drawImage(Image img, int x, int y,\r
+                             Color bgcolor,\r
+                             ImageObserver observer){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Draws as much of the specified image as has already been scaled\r
+     * to fit inside the specified rectangle.\r
+     * <p>\r
+     * The image is drawn inside the specified rectangle of this\r
+     * graphics context's coordinate space, and is scaled if\r
+     * necessary. Transparent pixels are drawn in the specified\r
+     * background color.\r
+     * This operation is equivalent to filling a rectangle of the\r
+     * width and height of the specified image with the given color and then\r
+     * drawing the image on top of it, but possibly more efficient.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * entire image has not yet been scaled, dithered, and converted\r
+     * for the current output device.\r
+     * If the current output representation is not yet complete then\r
+     * <code>drawImage</code> returns <code>false</code>. As more of\r
+     * the image becomes available, the process that draws the image notifies\r
+     * the specified image observer.\r
+     * <p>\r
+     * A scaled version of an image will not necessarily be\r
+     * available immediately just because an unscaled version of the\r
+     * image has been constructed for this output device.  Each size of\r
+     * the image may be cached separately and generated from the original\r
+     * data in a separate image production sequence.\r
+     * @param    img       the specified image to be drawn.\r
+     * @param    x         the <i>x</i> coordinate.\r
+     * @param    y         the <i>y</i> coordinate.\r
+     * @param    width     the width of the rectangle.\r
+     * @param    height    the height of the rectangle.\r
+     * @param    bgcolor   the background color to paint under the\r
+     *                         non-opaque portions of the image.\r
+     * @param    observer    object to be notified as more of\r
+     *                          the image is converted.\r
+     * @see      java.awt.Image\r
+     * @see      java.awt.image.ImageObserver\r
+     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     */\r
+    public boolean drawImage(Image img, int x, int y,\r
+                             int width, int height,\r
+                             Color bgcolor,\r
+                             ImageObserver observer){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+\r
+        return false;\r
+    }\r
+\r
+\r
+    /**\r
+     * Draws as much of the specified area of the specified image as is\r
+     * currently available, scaling it on the fly to fit inside the\r
+     * specified area of the destination drawable surface. Transparent pixels\r
+     * do not affect whatever pixels are already there.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * image area to be drawn has not yet been scaled, dithered, and converted\r
+     * for the current output device.\r
+     * If the current output representation is not yet complete then\r
+     * <code>drawImage</code> returns <code>false</code>. As more of\r
+     * the image becomes available, the process that draws the image notifies\r
+     * the specified image observer.\r
+     * <p>\r
+     * This method always uses the unscaled version of the image\r
+     * to render the scaled rectangle and performs the required\r
+     * scaling on the fly. It does not use a cached, scaled version\r
+     * of the image for this operation. Scaling of the image from source\r
+     * to destination is performed such that the first coordinate\r
+     * of the source rectangle is mapped to the first coordinate of\r
+     * the destination rectangle, and the second source coordinate is\r
+     * mapped to the second destination coordinate. The subimage is\r
+     * scaled and flipped as needed to preserve those mappings.\r
+     * @param       img the specified image to be drawn\r
+     * @param       dx1 the <i>x</i> coordinate of the first corner of the\r
+     *                    destination rectangle.\r
+     * @param       dy1 the <i>y</i> coordinate of the first corner of the\r
+     *                    destination rectangle.\r
+     * @param       dx2 the <i>x</i> coordinate of the second corner of the\r
+     *                    destination rectangle.\r
+     * @param       dy2 the <i>y</i> coordinate of the second corner of the\r
+     *                    destination rectangle.\r
+     * @param       sx1 the <i>x</i> coordinate of the first corner of the\r
+     *                    source rectangle.\r
+     * @param       sy1 the <i>y</i> coordinate of the first corner of the\r
+     *                    source rectangle.\r
+     * @param       sx2 the <i>x</i> coordinate of the second corner of the\r
+     *                    source rectangle.\r
+     * @param       sy2 the <i>y</i> coordinate of the second corner of the\r
+     *                    source rectangle.\r
+     * @param       observer object to be notified as more of the image is\r
+     *                    scaled and converted.\r
+     * @see         java.awt.Image\r
+     * @see         java.awt.image.ImageObserver\r
+     * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     * @since       JDK1.1\r
+     */\r
+    public boolean drawImage(Image img,\r
+                             int dx1, int dy1, int dx2, int dy2,\r
+                             int sx1, int sy1, int sx2, int sy2,\r
+                             ImageObserver observer){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Draws as much of the specified area of the specified image as is\r
+     * currently available, scaling it on the fly to fit inside the\r
+     * specified area of the destination drawable surface.\r
+     * <p>\r
+     * Transparent pixels are drawn in the specified background color.\r
+     * This operation is equivalent to filling a rectangle of the\r
+     * width and height of the specified image with the given color and then\r
+     * drawing the image on top of it, but possibly more efficient.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * image area to be drawn has not yet been scaled, dithered, and converted\r
+     * for the current output device.\r
+     * If the current output representation is not yet complete then\r
+     * <code>drawImage</code> returns <code>false</code>. As more of\r
+     * the image becomes available, the process that draws the image notifies\r
+     * the specified image observer.\r
+     * <p>\r
+     * This method always uses the unscaled version of the image\r
+     * to render the scaled rectangle and performs the required\r
+     * scaling on the fly. It does not use a cached, scaled version\r
+     * of the image for this operation. Scaling of the image from source\r
+     * to destination is performed such that the first coordinate\r
+     * of the source rectangle is mapped to the first coordinate of\r
+     * the destination rectangle, and the second source coordinate is\r
+     * mapped to the second destination coordinate. The subimage is\r
+     * scaled and flipped as needed to preserve those mappings.\r
+     * @param       img the specified image to be drawn\r
+     * @param       dx1 the <i>x</i> coordinate of the first corner of the\r
+     *                    destination rectangle.\r
+     * @param       dy1 the <i>y</i> coordinate of the first corner of the\r
+     *                    destination rectangle.\r
+     * @param       dx2 the <i>x</i> coordinate of the second corner of the\r
+     *                    destination rectangle.\r
+     * @param       dy2 the <i>y</i> coordinate of the second corner of the\r
+     *                    destination rectangle.\r
+     * @param       sx1 the <i>x</i> coordinate of the first corner of the\r
+     *                    source rectangle.\r
+     * @param       sy1 the <i>y</i> coordinate of the first corner of the\r
+     *                    source rectangle.\r
+     * @param       sx2 the <i>x</i> coordinate of the second corner of the\r
+     *                    source rectangle.\r
+     * @param       sy2 the <i>y</i> coordinate of the second corner of the\r
+     *                    source rectangle.\r
+     * @param       bgcolor the background color to paint under the\r
+     *                    non-opaque portions of the image.\r
+     * @param       observer object to be notified as more of the image is\r
+     *                    scaled and converted.\r
+     * @see         java.awt.Image\r
+     * @see         java.awt.image.ImageObserver\r
+     * @see         java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     * @since       JDK1.1\r
+     */\r
+    public boolean drawImage(Image img,\r
+                             int dx1, int dy1, int dx2, int dy2,\r
+                             int sx1, int sy1, int sx2, int sy2,\r
+                             Color bgcolor,\r
+                             ImageObserver observer){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Draws as much of the specified image as is currently available.\r
+     * The image is drawn with its top-left corner at\r
+     * (<i>x</i>,&nbsp;<i>y</i>) in this graphics context's coordinate\r
+     * space. Transparent pixels in the image do not affect whatever\r
+     * pixels are already there.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * complete image has not yet been loaded, and it has not been dithered\r
+     * and converted for the current output device.\r
+     * <p>\r
+     * If the image has completely loaded and its pixels are\r
+     * no longer being changed, then\r
+     * <code>drawImage</code> returns <code>true</code>.\r
+     * Otherwise, <code>drawImage</code> returns <code>false</code>\r
+     * and as more of\r
+     * the image becomes available\r
+     * or it is time to draw another frame of animation,\r
+     * the process that loads the image notifies\r
+     * the specified image observer.\r
+     * @param    img the specified image to be drawn. This method does\r
+     *               nothing if <code>img</code> is null.\r
+     * @param    x   the <i>x</i> coordinate.\r
+     * @param    y   the <i>y</i> coordinate.\r
+     * @param    observer    object to be notified as more of\r
+     *                          the image is converted.\r
+     * @return   <code>false</code> if the image pixels are still changing;\r
+     *           <code>true</code> otherwise.\r
+     * @see      java.awt.Image\r
+     * @see      java.awt.image.ImageObserver\r
+     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     */\r
+    public boolean drawImage(Image img, int x, int y,\r
+                             ImageObserver observer) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Disposes of this graphics context and releases\r
+     * any system resources that it is using.\r
+     * A <code>Graphics</code> object cannot be used after\r
+     * <code>dispose</code>has been called.\r
+     * <p>\r
+     * When a Java program runs, a large number of <code>Graphics</code>\r
+     * objects can be created within a short time frame.\r
+     * Although the finalization process of the garbage collector\r
+     * also disposes of the same system resources, it is preferable\r
+     * to manually free the associated resources by calling this\r
+     * method rather than to rely on a finalization process which\r
+     * may not run to completion for a long period of time.\r
+     * <p>\r
+     * Graphics objects which are provided as arguments to the\r
+     * <code>paint</code> and <code>update</code> methods\r
+     * of components are automatically released by the system when\r
+     * those methods return. For efficiency, programmers should\r
+     * call <code>dispose</code> when finished using\r
+     * a <code>Graphics</code> object only if it was created\r
+     * directly from a component or another <code>Graphics</code> object.\r
+     * @see         java.awt.Graphics#finalize\r
+     * @see         java.awt.Component#paint\r
+     * @see         java.awt.Component#update\r
+     * @see         java.awt.Component#getGraphics\r
+     * @see         java.awt.Graphics#create\r
+     */\r
+    public void dispose() {\r
+        ;\r
+    }\r
+\r
+    /**\r
+     * Draws a line, using the current color, between the points\r
+     * <code>(x1,&nbsp;y1)</code> and <code>(x2,&nbsp;y2)</code>\r
+     * in this graphics context's coordinate system.\r
+     * @param   x1  the first point's <i>x</i> coordinate.\r
+     * @param   y1  the first point's <i>y</i> coordinate.\r
+     * @param   x2  the second point's <i>x</i> coordinate.\r
+     * @param   y2  the second point's <i>y</i> coordinate.\r
+     */\r
+    public void drawLine(int x1, int y1, int x2, int y2){\r
+        Line2D line = new Line2D.Float(x1, y1, x2, y2);\r
+        draw(line);\r
+    }\r
+\r
+    /**\r
+     * Fills a closed polygon defined by\r
+     * arrays of <i>x</i> and <i>y</i> coordinates.\r
+     * <p>\r
+     * This method draws the polygon defined by <code>nPoint</code> line\r
+     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>\r
+     * line segments are line segments from\r
+     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>\r
+     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for\r
+     * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.\r
+     * The figure is automatically closed by drawing a line connecting\r
+     * the final point to the first point, if those points are different.\r
+     * <p>\r
+     * The area inside the polygon is defined using an\r
+     * even-odd fill rule, also known as the alternating rule.\r
+     * @param        xPoints   a an array of <code>x</code> coordinates.\r
+     * @param        yPoints   a an array of <code>y</code> coordinates.\r
+     * @param        nPoints   a the total number of points.\r
+     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)\r
+     */\r
+    public void fillPolygon(int[] xPoints, int[] yPoints,\r
+                            int nPoints){\r
+        java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);\r
+        fill(polygon);\r
+    }\r
+\r
+    /**\r
+     * Fills the specified rectangle.\r
+     * The left and right edges of the rectangle are at\r
+     * <code>x</code> and <code>x&nbsp;+&nbsp;width&nbsp;-&nbsp;1</code>.\r
+     * The top and bottom edges are at\r
+     * <code>y</code> and <code>y&nbsp;+&nbsp;height&nbsp;-&nbsp;1</code>.\r
+     * The resulting rectangle covers an area\r
+     * <code>width</code> pixels wide by\r
+     * <code>height</code> pixels tall.\r
+     * The rectangle is filled using the graphics context's current color.\r
+     * @param         x   the <i>x</i> coordinate\r
+     *                         of the rectangle to be filled.\r
+     * @param         y   the <i>y</i> coordinate\r
+     *                         of the rectangle to be filled.\r
+     * @param         width   the width of the rectangle to be filled.\r
+     * @param         height   the height of the rectangle to be filled.\r
+     * @see           java.awt.Graphics#clearRect\r
+     * @see           java.awt.Graphics#drawRect\r
+     */\r
+    public void fillRect(int x, int y, int width, int height){\r
+        Rectangle rect = new Rectangle(x, y, width, height);\r
+        fill(rect);\r
+    }\r
+\r
+    /**\r
+     * Draws the outline of the specified rectangle.\r
+     * The left and right edges of the rectangle are at\r
+     * <code>x</code> and <code>x&nbsp;+&nbsp;width</code>.\r
+     * The top and bottom edges are at\r
+     * <code>y</code> and <code>y&nbsp;+&nbsp;height</code>.\r
+     * The rectangle is drawn using the graphics context's current color.\r
+     * @param         x   the <i>x</i> coordinate\r
+     *                         of the rectangle to be drawn.\r
+     * @param         y   the <i>y</i> coordinate\r
+     *                         of the rectangle to be drawn.\r
+     * @param         width   the width of the rectangle to be drawn.\r
+     * @param         height   the height of the rectangle to be drawn.\r
+     * @see          java.awt.Graphics#fillRect\r
+     * @see          java.awt.Graphics#clearRect\r
+     */\r
+    public void drawRect(int x, int y, int width, int height) {\r
+        Rectangle rect = new Rectangle(x, y, width, height);\r
+        draw(rect);\r
+    }\r
+\r
+    /**\r
+     * Draws a closed polygon defined by\r
+     * arrays of <i>x</i> and <i>y</i> coordinates.\r
+     * Each pair of (<i>x</i>,&nbsp;<i>y</i>) coordinates defines a point.\r
+     * <p>\r
+     * This method draws the polygon defined by <code>nPoint</code> line\r
+     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>\r
+     * line segments are line segments from\r
+     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>\r
+     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for\r
+     * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.\r
+     * The figure is automatically closed by drawing a line connecting\r
+     * the final point to the first point, if those points are different.\r
+     * @param        xPoints   a an array of <code>x</code> coordinates.\r
+     * @param        yPoints   a an array of <code>y</code> coordinates.\r
+     * @param        nPoints   a the total number of points.\r
+     * @see          java.awt.Graphics#fillPolygon(int[],int[],int)\r
+     * @see          java.awt.Graphics#drawPolyline\r
+     */\r
+    public void drawPolygon(int[] xPoints, int[] yPoints,\r
+                            int nPoints){\r
+        java.awt.Polygon polygon = new java.awt.Polygon(xPoints, yPoints, nPoints);\r
+        draw(polygon);\r
+    }\r
+\r
+    /**\r
+     * Intersects the current clip with the specified rectangle.\r
+     * The resulting clipping area is the intersection of the current\r
+     * clipping area and the specified rectangle.  If there is no\r
+     * current clipping area, either because the clip has never been\r
+     * set, or the clip has been cleared using <code>setClip(null)</code>,\r
+     * the specified rectangle becomes the new clip.\r
+     * This method sets the user clip, which is independent of the\r
+     * clipping associated with device bounds and window visibility.\r
+     * This method can only be used to make the current clip smaller.\r
+     * To set the current clip larger, use any of the setClip methods.\r
+     * Rendering operations have no effect outside of the clipping area.\r
+     * @param x the x coordinate of the rectangle to intersect the clip with\r
+     * @param y the y coordinate of the rectangle to intersect the clip with\r
+     * @param width the width of the rectangle to intersect the clip with\r
+     * @param height the height of the rectangle to intersect the clip with\r
+     * @see #setClip(int, int, int, int)\r
+     * @see #setClip(Shape)\r
+     */\r
+    public void clipRect(int x, int y, int width, int height){\r
+        clip(new Rectangle(x, y, width, height));\r
+    }\r
+\r
+    /**\r
+     * Sets the current clipping area to an arbitrary clip shape.\r
+     * Not all objects that implement the <code>Shape</code>\r
+     * interface can be used to set the clip.  The only\r
+     * <code>Shape</code> objects that are guaranteed to be\r
+     * supported are <code>Shape</code> objects that are\r
+     * obtained via the <code>getClip</code> method and via\r
+     * <code>Rectangle</code> objects.  This method sets the\r
+     * user clip, which is independent of the clipping associated\r
+     * with device bounds and window visibility.\r
+     * @param clip the <code>Shape</code> to use to set the clip\r
+     * @see         java.awt.Graphics#getClip()\r
+     * @see         java.awt.Graphics#clipRect\r
+     * @see         java.awt.Graphics#setClip(int, int, int, int)\r
+     * @since       JDK1.1\r
+     */\r
+    public void setClip(Shape clip) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the bounding rectangle of the current clipping area.\r
+     * This method refers to the user clip, which is independent of the\r
+     * clipping associated with device bounds and window visibility.\r
+     * If no clip has previously been set, or if the clip has been\r
+     * cleared using <code>setClip(null)</code>, this method returns\r
+     * <code>null</code>.\r
+     * The coordinates in the rectangle are relative to the coordinate\r
+     * system origin of this graphics context.\r
+     * @return      the bounding rectangle of the current clipping area,\r
+     *              or <code>null</code> if no clip is set.\r
+     * @see         java.awt.Graphics#getClip\r
+     * @see         java.awt.Graphics#clipRect\r
+     * @see         java.awt.Graphics#setClip(int, int, int, int)\r
+     * @see         java.awt.Graphics#setClip(Shape)\r
+     * @since       JDK1.1\r
+     */\r
+    public Rectangle getClipBounds(){\r
+        Shape c = getClip();\r
+        if (c==null) {\r
+            return null;\r
+        }\r
+        return c.getBounds();\r
+    }\r
+\r
+    /**\r
+     * Draws the text given by the specified iterator, using this\r
+     * graphics context's current color. The iterator has to specify a font\r
+     * for each character. The baseline of the\r
+     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in this\r
+     * graphics context's coordinate system.\r
+     * @param       iterator the iterator whose text is to be drawn\r
+     * @param       x        the <i>x</i> coordinate.\r
+     * @param       y        the <i>y</i> coordinate.\r
+     * @see         java.awt.Graphics#drawBytes\r
+     * @see         java.awt.Graphics#drawChars\r
+     */\r
+    public void drawString(AttributedCharacterIterator iterator,\r
+                           int x, int y){\r
+        drawString(iterator, (float)x, (float)y);\r
+    }\r
+\r
+    /**\r
+     * Clears the specified rectangle by filling it with the background\r
+     * color of the current drawing surface. This operation does not\r
+     * use the current paint mode.\r
+     * <p>\r
+     * Beginning with Java&nbsp;1.1, the background color\r
+     * of offscreen images may be system dependent. Applications should\r
+     * use <code>setColor</code> followed by <code>fillRect</code> to\r
+     * ensure that an offscreen image is cleared to a specific color.\r
+     * @param       x the <i>x</i> coordinate of the rectangle to clear.\r
+     * @param       y the <i>y</i> coordinate of the rectangle to clear.\r
+     * @param       width the width of the rectangle to clear.\r
+     * @param       height the height of the rectangle to clear.\r
+     * @see         java.awt.Graphics#fillRect(int, int, int, int)\r
+     * @see         java.awt.Graphics#drawRect\r
+     * @see         java.awt.Graphics#setColor(java.awt.Color)\r
+     * @see         java.awt.Graphics#setPaintMode\r
+     * @see         java.awt.Graphics#setXORMode(java.awt.Color)\r
+     */\r
+    public void clearRect(int x, int y, int width, int height) {\r
+        Paint paint = getPaint();\r
+        setColor(getBackground());\r
+        fillRect(x, y, width, height);\r
+        setPaint(paint);\r
+    }\r
+\r
+    public void copyArea(int x, int y, int width, int height, int dx, int dy) {\r
+        ;\r
+    }\r
+\r
+    /**\r
+     * Sets the current clip to the rectangle specified by the given\r
+     * coordinates.  This method sets the user clip, which is\r
+     * independent of the clipping associated with device bounds\r
+     * and window visibility.\r
+     * Rendering operations have no effect outside of the clipping area.\r
+     * @param       x the <i>x</i> coordinate of the new clip rectangle.\r
+     * @param       y the <i>y</i> coordinate of the new clip rectangle.\r
+     * @param       width the width of the new clip rectangle.\r
+     * @param       height the height of the new clip rectangle.\r
+     * @see         java.awt.Graphics#clipRect\r
+     * @see         java.awt.Graphics#setClip(Shape)\r
+     * @since       JDK1.1\r
+     */\r
+    public void setClip(int x, int y, int width, int height){\r
+        setClip(new Rectangle(x, y, width, height));\r
+    }\r
+\r
+    /**\r
+     * Concatenates the current <code>Graphics2D</code>\r
+     * <code>Transform</code> with a rotation transform.\r
+     * Subsequent rendering is rotated by the specified radians relative\r
+     * to the previous origin.\r
+     * This is equivalent to calling <code>transform(R)</code>, where R is an\r
+     * <code>AffineTransform</code> represented by the following matrix:\r
+     * <pre>\r
+     *          [   cos(theta)    -sin(theta)    0   ]\r
+     *          [   sin(theta)     cos(theta)    0   ]\r
+     *          [       0              0         1   ]\r
+     * </pre>\r
+     * Rotating with a positive angle theta rotates points on the positive\r
+     * x axis toward the positive y axis.\r
+     * @param theta the angle of rotation in radians\r
+     */\r
+    public void rotate(double theta){\r
+        _transform.rotate(theta);\r
+    }\r
+\r
+    /**\r
+     * Concatenates the current <code>Graphics2D</code>\r
+     * <code>Transform</code> with a translated rotation\r
+     * transform.  Subsequent rendering is transformed by a transform\r
+     * which is constructed by translating to the specified location,\r
+     * rotating by the specified radians, and translating back by the same\r
+     * amount as the original translation.  This is equivalent to the\r
+     * following sequence of calls:\r
+     * <pre>\r
+     *          translate(x, y);\r
+     *          rotate(theta);\r
+     *          translate(-x, -y);\r
+     * </pre>\r
+     * Rotating with a positive angle theta rotates points on the positive\r
+     * x axis toward the positive y axis.\r
+     * @param theta the angle of rotation in radians\r
+     * @param x x coordinate of the origin of the rotation\r
+     * @param y y coordinate of the origin of the rotation\r
+     */\r
+    public void rotate(double theta, double x, double y){\r
+        _transform.rotate(theta, x, y);\r
+    }\r
+\r
+    /**\r
+     * Concatenates the current <code>Graphics2D</code>\r
+     * <code>Transform</code> with a shearing transform.\r
+     * Subsequent renderings are sheared by the specified\r
+     * multiplier relative to the previous position.\r
+     * This is equivalent to calling <code>transform(SH)</code>, where SH\r
+     * is an <code>AffineTransform</code> represented by the following\r
+     * matrix:\r
+     * <pre>\r
+     *          [   1   shx   0   ]\r
+     *          [  shy   1    0   ]\r
+     *          [   0    0    1   ]\r
+     * </pre>\r
+     * @param shx the multiplier by which coordinates are shifted in\r
+     * the positive X axis direction as a function of their Y coordinate\r
+     * @param shy the multiplier by which coordinates are shifted in\r
+     * the positive Y axis direction as a function of their X coordinate\r
+     */\r
+    public void shear(double shx, double shy){\r
+        _transform.shear(shx, shy);\r
+    }\r
+\r
+    /**\r
+     * Get the rendering context of the <code>Font</code> within this\r
+     * <code>Graphics2D</code> context.\r
+     * The {@link FontRenderContext}\r
+     * encapsulates application hints such as anti-aliasing and\r
+     * fractional metrics, as well as target device specific information\r
+     * such as dots-per-inch.  This information should be provided by the\r
+     * application when using objects that perform typographical\r
+     * formatting, such as <code>Font</code> and\r
+     * <code>TextLayout</code>.  This information should also be provided\r
+     * by applications that perform their own layout and need accurate\r
+     * measurements of various characteristics of glyphs such as advance\r
+     * and line height when various rendering hints have been applied to\r
+     * the text rendering.\r
+     *\r
+     * @return a reference to an instance of FontRenderContext.\r
+     * @see java.awt.font.FontRenderContext\r
+     * @see java.awt.Font#createGlyphVector(FontRenderContext,char[])\r
+     * @see java.awt.font.TextLayout\r
+     * @since     JDK1.2\r
+     */\r
+    public FontRenderContext getFontRenderContext() {\r
+        boolean isAntiAliased = RenderingHints.VALUE_TEXT_ANTIALIAS_ON.equals(\r
+                getRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING));\r
+        boolean usesFractionalMetrics = RenderingHints.VALUE_FRACTIONALMETRICS_ON.equals(\r
+                getRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS));\r
+\r
+\r
+        return new FontRenderContext(new AffineTransform(), isAntiAliased, usesFractionalMetrics);\r
+    }\r
+\r
+    /**\r
+     * Composes an <code>AffineTransform</code> object with the\r
+     * <code>Transform</code> in this <code>Graphics2D</code> according\r
+     * to the rule last-specified-first-applied.  If the current\r
+     * <code>Transform</code> is Cx, the result of composition\r
+     * with Tx is a new <code>Transform</code> Cx'.  Cx' becomes the\r
+     * current <code>Transform</code> for this <code>Graphics2D</code>.\r
+     * Transforming a point p by the updated <code>Transform</code> Cx' is\r
+     * equivalent to first transforming p by Tx and then transforming\r
+     * the result by the original <code>Transform</code> Cx.  In other\r
+     * words, Cx'(p) = Cx(Tx(p)).  A copy of the Tx is made, if necessary,\r
+     * so further modifications to Tx do not affect rendering.\r
+     * @param Tx the <code>AffineTransform</code> object to be composed with\r
+     * the current <code>Transform</code>\r
+     * @see #setTransform\r
+     * @see AffineTransform\r
+     */\r
+    public void transform(AffineTransform Tx) {\r
+        _transform.concatenate(Tx);\r
+    }\r
+\r
+    /**\r
+     * Renders a <code>BufferedImage</code> that is\r
+     * filtered with a\r
+     * {@link BufferedImageOp}.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>\r
+     * and <code>Composite</code> attributes.  This is equivalent to:\r
+     * <pre>\r
+     * img1 = op.filter(img, null);\r
+     * drawImage(img1, new AffineTransform(1f,0f,0f,1f,x,y), null);\r
+     * </pre>\r
+     * @param img the <code>BufferedImage</code> to be rendered\r
+     * @param op the filter to be applied to the image before rendering\r
+     * @param x the x coordinate in user space where the image is rendered\r
+     * @param y the y coordinate in user space where the image is rendered\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #clip\r
+     * @see #setClip(Shape)\r
+     */\r
+    public void drawImage(BufferedImage img,\r
+                          BufferedImageOp op,\r
+                          int x,\r
+                          int y){\r
+        img = op.filter(img, null);\r
+        drawImage(img, x, y, null);\r
+    }\r
+\r
+    /**\r
+     * Sets the background color for the <code>Graphics2D</code> context.\r
+     * The background color is used for clearing a region.\r
+     * When a <code>Graphics2D</code> is constructed for a\r
+     * <code>Component</code>, the background color is\r
+     * inherited from the <code>Component</code>. Setting the background color\r
+     * in the <code>Graphics2D</code> context only affects the subsequent\r
+     * <code>clearRect</code> calls and not the background color of the\r
+     * <code>Component</code>.  To change the background\r
+     * of the <code>Component</code>, use appropriate methods of\r
+     * the <code>Component</code>.\r
+     * @param color the background color that isused in\r
+     * subsequent calls to <code>clearRect</code>\r
+     * @see #getBackground\r
+     * @see java.awt.Graphics#clearRect\r
+     */\r
+    public void setBackground(Color color) {\r
+        if(color == null)\r
+            return;\r
+\r
+        _background = color;\r
+    }\r
+\r
+    /**\r
+     * Returns the background color used for clearing a region.\r
+     * @return the current <code>Graphics2D</code> <code>Color</code>,\r
+     * which defines the background color.\r
+     * @see #setBackground\r
+     */\r
+    public Color getBackground(){\r
+        return _background;\r
+    }\r
+\r
+    /**\r
+     * Sets the <code>Composite</code> for the <code>Graphics2D</code> context.\r
+     * The <code>Composite</code> is used in all drawing methods such as\r
+     * <code>drawImage</code>, <code>drawString</code>, <code>draw</code>,\r
+     * and <code>fill</code>.  It specifies how new pixels are to be combined\r
+     * with the existing pixels on the graphics device during the rendering\r
+     * process.\r
+     * <p>If this <code>Graphics2D</code> context is drawing to a\r
+     * <code>Component</code> on the display screen and the\r
+     * <code>Composite</code> is a custom object rather than an\r
+     * instance of the <code>AlphaComposite</code> class, and if\r
+     * there is a security manager, its <code>checkPermission</code>\r
+     * method is called with an <code>AWTPermission("readDisplayPixels")</code>\r
+     * permission.\r
+     *\r
+     * @param comp the <code>Composite</code> object to be used for rendering\r
+     * @throws SecurityException\r
+     *         if a custom <code>Composite</code> object is being\r
+     *         used to render to the screen and a security manager\r
+     *         is set and its <code>checkPermission</code> method\r
+     *         does not allow the operation.\r
+     * @see java.awt.Graphics#setXORMode\r
+     * @see java.awt.Graphics#setPaintMode\r
+     * @see java.awt.AlphaComposite\r
+     */\r
+    public void setComposite(Composite comp){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the current <code>Composite</code> in the\r
+     * <code>Graphics2D</code> context.\r
+     * @return the current <code>Graphics2D</code> <code>Composite</code>,\r
+     *              which defines a compositing style.\r
+     * @see #setComposite\r
+     */\r
+    public Composite getComposite(){\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Returns the value of a single preference for the rendering algorithms.\r
+     * Hint categories include controls for rendering quality and overall\r
+     * time/quality trade-off in the rendering process.  Refer to the\r
+     * <code>RenderingHints</code> class for definitions of some common\r
+     * keys and values.\r
+     * @param hintKey the key corresponding to the hint to get.\r
+     * @return an object representing the value for the specified hint key.\r
+     * Some of the keys and their associated values are defined in the\r
+     * <code>RenderingHints</code> class.\r
+     * @see RenderingHints\r
+     */\r
+    public Object getRenderingHint(RenderingHints.Key hintKey){\r
+        return _hints.get(hintKey);\r
+    }\r
+\r
+    /**\r
+     * Sets the value of a single preference for the rendering algorithms.\r
+     * Hint categories include controls for rendering quality and overall\r
+     * time/quality trade-off in the rendering process.  Refer to the\r
+     * <code>RenderingHints</code> class for definitions of some common\r
+     * keys and values.\r
+     * @param hintKey the key of the hint to be set.\r
+     * @param hintValue the value indicating preferences for the specified\r
+     * hint category.\r
+     * @see RenderingHints\r
+     */\r
+    public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue){\r
+        _hints.put(hintKey, hintValue);\r
+    }\r
+\r
+\r
+    /**\r
+     * Renders the text of the specified\r
+     * {@link GlyphVector} using\r
+     * the <code>Graphics2D</code> context's rendering attributes.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, <code>Paint</code>, and\r
+     * <code>Composite</code> attributes.  The <code>GlyphVector</code>\r
+     * specifies individual glyphs from a {@link Font}.\r
+     * The <code>GlyphVector</code> can also contain the glyph positions.\r
+     * This is the fastest way to render a set of characters to the\r
+     * screen.\r
+     *\r
+     * @param g the <code>GlyphVector</code> to be rendered\r
+     * @param x the x position in user space where the glyphs should be\r
+     *        rendered\r
+     * @param y the y position in user space where the glyphs should be\r
+     *        rendered\r
+     *\r
+     * @see java.awt.Font#createGlyphVector(FontRenderContext, char[])\r
+     * @see java.awt.font.GlyphVector\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #setClip(Shape)\r
+     */\r
+    public void drawGlyphVector(GlyphVector g, float x, float y) {\r
+        Shape glyphOutline = g.getOutline(x, y);\r
+        fill(glyphOutline);\r
+    }\r
+\r
+    /**\r
+     * Returns the device configuration associated with this\r
+     * <code>Graphics2D</code>.\r
+     * @return the device configuration\r
+     */\r
+    public GraphicsConfiguration getDeviceConfiguration() {\r
+        return GraphicsEnvironment.getLocalGraphicsEnvironment().\r
+                getDefaultScreenDevice().getDefaultConfiguration();\r
+    }\r
+\r
+    /**\r
+     * Sets the values of an arbitrary number of preferences for the\r
+     * rendering algorithms.\r
+     * Only values for the rendering hints that are present in the\r
+     * specified <code>Map</code> object are modified.\r
+     * All other preferences not present in the specified\r
+     * object are left unmodified.\r
+     * Hint categories include controls for rendering quality and\r
+     * overall time/quality trade-off in the rendering process.\r
+     * Refer to the <code>RenderingHints</code> class for definitions of\r
+     * some common keys and values.\r
+     * @param hints the rendering hints to be set\r
+     * @see RenderingHints\r
+     */\r
+    public void addRenderingHints(Map<?,?> hints){\r
+        this._hints.putAll(hints);\r
+    }\r
+\r
+    /**\r
+     * Concatenates the current\r
+     * <code>Graphics2D</code> <code>Transform</code>\r
+     * with a translation transform.\r
+     * Subsequent rendering is translated by the specified\r
+     * distance relative to the previous position.\r
+     * This is equivalent to calling transform(T), where T is an\r
+     * <code>AffineTransform</code> represented by the following matrix:\r
+     * <pre>\r
+     *          [   1    0    tx  ]\r
+     *          [   0    1    ty  ]\r
+     *          [   0    0    1   ]\r
+     * </pre>\r
+     * @param tx the distance to translate along the x-axis\r
+     * @param ty the distance to translate along the y-axis\r
+     */\r
+    public void translate(double tx, double ty){\r
+        _transform.translate(tx, ty);\r
+    }\r
+\r
+    /**\r
+     * Renders the text of the specified iterator, using the\r
+     * <code>Graphics2D</code> context's current <code>Paint</code>. The\r
+     * iterator must specify a font\r
+     * for each character. The baseline of the\r
+     * first character is at position (<i>x</i>,&nbsp;<i>y</i>) in the\r
+     * User Space.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, <code>Paint</code>, and\r
+     * <code>Composite</code> attributes.\r
+     * For characters in script systems such as Hebrew and Arabic,\r
+     * the glyphs can be rendered from right to left, in which case the\r
+     * coordinate supplied is the location of the leftmost character\r
+     * on the baseline.\r
+     * @param iterator the iterator whose text is to be rendered\r
+     * @param x the x coordinate where the iterator's text is to be\r
+     * rendered\r
+     * @param y the y coordinate where the iterator's text is to be\r
+     * rendered\r
+     * @see #setPaint\r
+     * @see java.awt.Graphics#setColor\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #setClip\r
+     */\r
+    public void drawString(AttributedCharacterIterator iterator, float x, float y) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Checks whether or not the specified <code>Shape</code> intersects\r
+     * the specified {@link Rectangle}, which is in device\r
+     * space. If <code>onStroke</code> is false, this method checks\r
+     * whether or not the interior of the specified <code>Shape</code>\r
+     * intersects the specified <code>Rectangle</code>.  If\r
+     * <code>onStroke</code> is <code>true</code>, this method checks\r
+     * whether or not the <code>Stroke</code> of the specified\r
+     * <code>Shape</code> outline intersects the specified\r
+     * <code>Rectangle</code>.\r
+     * The rendering attributes taken into account include the\r
+     * <code>Clip</code>, <code>Transform</code>, and <code>Stroke</code>\r
+     * attributes.\r
+     * @param rect the area in device space to check for a hit\r
+     * @param s the <code>Shape</code> to check for a hit\r
+     * @param onStroke flag used to choose between testing the\r
+     * stroked or the filled shape.  If the flag is <code>true</code>, the\r
+     * <code>Stroke</code> oultine is tested.  If the flag is\r
+     * <code>false</code>, the filled <code>Shape</code> is tested.\r
+     * @return <code>true</code> if there is a hit; <code>false</code>\r
+     * otherwise.\r
+     * @see #setStroke\r
+     * @see #fill(Shape)\r
+     * @see #draw(Shape)\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #clip\r
+     * @see #setClip(Shape)\r
+     */\r
+    public boolean hit(Rectangle rect,\r
+                       Shape s,\r
+                       boolean onStroke){\r
+        if (onStroke) {\r
+            s = getStroke().createStrokedShape(s);\r
+        }\r
+\r
+        s = getTransform().createTransformedShape(s);\r
+\r
+        return s.intersects(rect);\r
+    }\r
+\r
+    /**\r
+     * Gets the preferences for the rendering algorithms.  Hint categories\r
+     * include controls for rendering quality and overall time/quality\r
+     * trade-off in the rendering process.\r
+     * Returns all of the hint key/value pairs that were ever specified in\r
+     * one operation.  Refer to the\r
+     * <code>RenderingHints</code> class for definitions of some common\r
+     * keys and values.\r
+     * @return a reference to an instance of <code>RenderingHints</code>\r
+     * that contains the current preferences.\r
+     * @see RenderingHints\r
+     */\r
+    public RenderingHints getRenderingHints(){\r
+        return _hints;\r
+    }\r
+\r
+    /**\r
+     * Replaces the values of all preferences for the rendering\r
+     * algorithms with the specified <code>hints</code>.\r
+     * The existing values for all rendering hints are discarded and\r
+     * the new set of known hints and values are initialized from the\r
+     * specified {@link Map} object.\r
+     * Hint categories include controls for rendering quality and\r
+     * overall time/quality trade-off in the rendering process.\r
+     * Refer to the <code>RenderingHints</code> class for definitions of\r
+     * some common keys and values.\r
+     * @param hints the rendering hints to be set\r
+     * @see RenderingHints\r
+     */\r
+    public void setRenderingHints(Map<?,?> hints){\r
+        this._hints = new RenderingHints(null);\r
+        this._hints.putAll(hints);\r
+    }\r
+\r
+    /**\r
+     * Renders an image, applying a transform from image space into user space\r
+     * before drawing.\r
+     * The transformation from user space into device space is done with\r
+     * the current <code>Transform</code> in the <code>Graphics2D</code>.\r
+     * The specified transformation is applied to the image before the\r
+     * transform attribute in the <code>Graphics2D</code> context is applied.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, and <code>Composite</code> attributes.\r
+     * Note that no rendering is done if the specified transform is\r
+     * noninvertible.\r
+     * @param img the <code>Image</code> to be rendered\r
+     * @param xform the transformation from image space into user space\r
+     * @param obs the {@link ImageObserver}\r
+     * to be notified as more of the <code>Image</code>\r
+     * is converted\r
+     * @return <code>true</code> if the <code>Image</code> is\r
+     * fully loaded and completely rendered;\r
+     * <code>false</code> if the <code>Image</code> is still being loaded.\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #clip\r
+     * @see #setClip(Shape)\r
+     */\r
+     public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {\r
+         if (log.check(POILogger.WARN)) {\r
+             log.log(POILogger.WARN, "Not implemented");\r
+         }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Draws as much of the specified image as has already been scaled\r
+     * to fit inside the specified rectangle.\r
+     * <p>\r
+     * The image is drawn inside the specified rectangle of this\r
+     * graphics context's coordinate space, and is scaled if\r
+     * necessary. Transparent pixels do not affect whatever pixels\r
+     * are already there.\r
+     * <p>\r
+     * This method returns immediately in all cases, even if the\r
+     * entire image has not yet been scaled, dithered, and converted\r
+     * for the current output device.\r
+     * If the current output representation is not yet complete, then\r
+     * <code>drawImage</code> returns <code>false</code>. As more of\r
+     * the image becomes available, the process that loads the image notifies\r
+     * the image observer by calling its <code>imageUpdate</code> method.\r
+     * <p>\r
+     * A scaled version of an image will not necessarily be\r
+     * available immediately just because an unscaled version of the\r
+     * image has been constructed for this output device.  Each size of\r
+     * the image may be cached separately and generated from the original\r
+     * data in a separate image production sequence.\r
+     * @param    img    the specified image to be drawn. This method does\r
+     *                  nothing if <code>img</code> is null.\r
+     * @param    x      the <i>x</i> coordinate.\r
+     * @param    y      the <i>y</i> coordinate.\r
+     * @param    width  the width of the rectangle.\r
+     * @param    height the height of the rectangle.\r
+     * @param    observer    object to be notified as more of\r
+     *                          the image is converted.\r
+     * @return   <code>false</code> if the image pixels are still changing;\r
+     *           <code>true</code> otherwise.\r
+     * @see      java.awt.Image\r
+     * @see      java.awt.image.ImageObserver\r
+     * @see      java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int)\r
+     */\r
+    public boolean drawImage(Image img, int x, int y,\r
+                             int width, int height,\r
+                             ImageObserver observer) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+        return false;\r
+    }\r
+\r
+    /**\r
+     * Creates a new <code>Graphics</code> object that is\r
+     * a copy of this <code>Graphics</code> object.\r
+     * @return     a new graphics context that is a copy of\r
+     *                       this graphics context.\r
+     */\r
+    public Graphics create() {\r
+        try {\r
+            return (Graphics)clone();\r
+        } catch (CloneNotSupportedException e){\r
+            throw new RuntimeException(e);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Gets the font metrics for the specified font.\r
+     * @return    the font metrics for the specified font.\r
+     * @param     f the specified font\r
+     * @see       java.awt.Graphics#getFont\r
+     * @see       java.awt.FontMetrics\r
+     * @see       java.awt.Graphics#getFontMetrics()\r
+     */\r
+    @SuppressWarnings("deprecation")\r
+    @SuppressForbidden\r
+    public FontMetrics getFontMetrics(Font f) {\r
+        return Toolkit.getDefaultToolkit().getFontMetrics(f);\r
+    }\r
+\r
+    /**\r
+     * Sets the paint mode of this graphics context to alternate between\r
+     * this graphics context's current color and the new specified color.\r
+     * This specifies that logical pixel operations are performed in the\r
+     * XOR mode, which alternates pixels between the current color and\r
+     * a specified XOR color.\r
+     * <p>\r
+     * When drawing operations are performed, pixels which are the\r
+     * current color are changed to the specified color, and vice versa.\r
+     * <p>\r
+     * Pixels that are of colors other than those two colors are changed\r
+     * in an unpredictable but reversible manner; if the same figure is\r
+     * drawn twice, then all pixels are restored to their original values.\r
+     * @param     c1 the XOR alternation color\r
+     */\r
+    public void setXORMode(Color c1) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Sets the paint mode of this graphics context to overwrite the\r
+     * destination with this graphics context's current color.\r
+     * This sets the logical pixel operation function to the paint or\r
+     * overwrite mode.  All subsequent rendering operations will\r
+     * overwrite the destination with the current color.\r
+     */\r
+    public void setPaintMode() {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Renders a\r
+     * {@link RenderableImage},\r
+     * applying a transform from image space into user space before drawing.\r
+     * The transformation from user space into device space is done with\r
+     * the current <code>Transform</code> in the <code>Graphics2D</code>.\r
+     * The specified transformation is applied to the image before the\r
+     * transform attribute in the <code>Graphics2D</code> context is applied.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, and <code>Composite</code> attributes. Note\r
+     * that no rendering is done if the specified transform is\r
+     * noninvertible.\r
+     *<p>\r
+     * Rendering hints set on the <code>Graphics2D</code> object might\r
+     * be used in rendering the <code>RenderableImage</code>.\r
+     * If explicit control is required over specific hints recognized by a\r
+     * specific <code>RenderableImage</code>, or if knowledge of which hints\r
+     * are used is required, then a <code>RenderedImage</code> should be\r
+     * obtained directly from the <code>RenderableImage</code>\r
+     * and rendered using\r
+     *{@link #drawRenderedImage(RenderedImage, AffineTransform) drawRenderedImage}.\r
+     * @param img the image to be rendered. This method does\r
+     *            nothing if <code>img</code> is null.\r
+     * @param xform the transformation from image space into user space\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #clip\r
+     * @see #setClip\r
+     * @see #drawRenderedImage\r
+     */\r
+     public void drawRenderedImage(RenderedImage img, AffineTransform xform) {\r
+         if (log.check(POILogger.WARN)) {\r
+             log.log(POILogger.WARN, "Not implemented");\r
+         }\r
+    }\r
+\r
+    /**\r
+     * Renders a {@link RenderedImage},\r
+     * applying a transform from image\r
+     * space into user space before drawing.\r
+     * The transformation from user space into device space is done with\r
+     * the current <code>Transform</code> in the <code>Graphics2D</code>.\r
+     * The specified transformation is applied to the image before the\r
+     * transform attribute in the <code>Graphics2D</code> context is applied.\r
+     * The rendering attributes applied include the <code>Clip</code>,\r
+     * <code>Transform</code>, and <code>Composite</code> attributes. Note\r
+     * that no rendering is done if the specified transform is\r
+     * noninvertible.\r
+     * @param img the image to be rendered. This method does\r
+     *            nothing if <code>img</code> is null.\r
+     * @param xform the transformation from image space into user space\r
+     * @see #_transform\r
+     * @see #setTransform\r
+     * @see #setComposite\r
+     * @see #clip\r
+     * @see #setClip\r
+     */\r
+    public void drawRenderableImage(RenderableImage img, AffineTransform xform) {\r
+        if (log.check(POILogger.WARN)) {\r
+            log.log(POILogger.WARN, "Not implemented");\r
+        }\r
+    }\r
+\r
+    protected void applyStroke(SimpleShape<?,?> shape) {\r
+        if (_stroke instanceof BasicStroke){\r
+            BasicStroke bs = (BasicStroke)_stroke;\r
+            shape.setStrokeStyle((double)bs.getLineWidth());\r
+            float[] dash = bs.getDashArray();\r
+            if (dash != null) {\r
+                //TODO: implement more dashing styles\r
+                shape.setStrokeStyle(StrokeStyle.LineDash.DASH);\r
+            }\r
+        }\r
+    }\r
+\r
+    protected void applyPaint(SimpleShape<?,?> shape) {\r
+        if (_paint instanceof Color) {\r
+            shape.setFillColor((Color)_paint);\r
+        }\r
+    }\r
+}\r
index ceed729e09710a78b877769f6cb3bb12a3049c6b..8ed151b496ee5dc703dd012855a64312e81589c6 100644 (file)
@@ -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<S,P>,
     P extends TextParagraph<S,P,?>
 > extends Shape<S,P>, IAdjustableShape, PlaceableShape<S,P> {
+
+    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<S,P> 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 <code>null</code> unsets
+     *              the solid fill attribute from the underlying implementation
+     */
+       void setFillColor(Color color);
 }
index 53449e76d5c4de290ee01c05f4c3079fd4406f39..968911b95f19eeb22d3eb532bcd5b06cd2979e6d 100644 (file)
@@ -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.
index 244173fed43cc51749235829590403fdc65bb5eb..be93a994dea0b7c905e63d50d65eb467c7f818a6 100644 (file)
@@ -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;
+        }
     }
 
 
index 278573bab503819ecd329b1105eca987482bfe48..5ad4c4c296ee83c9a712076f9678f7249eeb78a7 100644 (file)
 \r
 package org.apache.poi.sl.usermodel;\r
 \r
+import java.awt.Color;\r
+\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
+\r
 public interface TableCell<\r
     S extends Shape<S,P>,\r
     P extends TextParagraph<S,P,?>\r
 > extends TextShape<S,P> {\r
+    enum BorderEdge { bottom, left, top, right };\r
+    \r
+    /**\r
+     * Return line style of given edge or {@code null} if border is not defined\r
+     *\r
+     * @param edge the border edge\r
+     * @return line style of given edge or {@code null} if border is not defined\r
+     */\r
+    StrokeStyle getBorderStyle(BorderEdge edge);\r
+    \r
+    /**\r
+     * Sets the {@link StrokeStyle} of the given border edge.\r
+     * A {@code null} property of the style is ignored.\r
+     *\r
+     * @param edge border edge\r
+     * @param style the new stroke style\r
+     */\r
+    void setBorderStyle(BorderEdge edge, StrokeStyle style);\r
+    \r
+    /**\r
+     * Convenience method for setting the border width.\r
+     *\r
+     * @param edge border edge\r
+     * @param width the new border width\r
+     */\r
+    void setBorderWidth(BorderEdge edge, double width);\r
+\r
+    /**\r
+     * Convenience method for setting the border color.\r
+     *\r
+     * @param edge border edge\r
+     * @param color the new border color\r
+     */\r
+    void setBorderColor(BorderEdge edge, Color color);\r
+\r
+    /**\r
+     * Convenience method for setting the border line compound.\r
+     *\r
+     * @param edge border edge\r
+     * @param compound the new border line compound\r
+     */\r
+    void setBorderCompound(BorderEdge edge, LineCompound compound);\r
 \r
+    /**\r
+     * Convenience method for setting the border line dash.\r
+     *\r
+     * @param edge border edge\r
+     * @param dash the new border line dash\r
+     */\r
+    void setBorderDash(BorderEdge edge, LineDash dash);\r
+    \r
+    /**\r
+     * Remove all line attributes of the given border edge\r
+     *\r
+     * @param edge the border edge to be cleared\r
+     */\r
+    void removeBorder(BorderEdge edge);\r
 }\r
index 29342e7d943423ee90f27eb490fbbcc95508a82d..561448446793d784f352322b1998ceaf84b95caf 100644 (file)
@@ -21,5 +21,25 @@ public interface TableShape<
     S extends Shape<S,P>,\r
     P extends TextParagraph<S,P,?>\r
 > extends Shape<S,P>, PlaceableShape<S,P> {\r
-    // to be defined ...\r
+    int getNumberOfColumns();\r
+    \r
+    int getNumberOfRows();\r
+    \r
+    TableCell<S,P> getCell(int row, int col);\r
+    \r
+    /**\r
+     * Sets the width (in points) of the n-th column\r
+     *\r
+     * @param idx the column index (0-based)\r
+     * @param width the width (in points)\r
+     */\r
+    void setColumnWidth(int idx, double width);\r
+\r
+    /**\r
+     * Sets the row height.\r
+     *\r
+     * @param row the row index (0-based)\r
+     * @param height the height to set (in points)\r
+     */\r
+    void setRowHeight(int row, double height);\r
 }\r
index 8fa997c89e22cbf987727ca0919100f14da51820..bc6951103a84073394b957d253f8255ad202c290 100644 (file)
 
 package org.apache.poi.sl.usermodel;
 
+/**
+ * Represents a TextFrame shape in PowerPoint.
+ * <p>
+ * Contains the text in a text frame as well as the properties and methods
+ * that control alignment and anchoring of the text.
+ * </p>
+ */
 public interface TextBox<
     S extends Shape<S,P>,
     P extends TextParagraph<S,P,?>
index 00a016058d1565082f3cea3f79a83f7d8d91821b..b35d323e1a73b438b2c34b333540e40e721911e1 100644 (file)
@@ -18,6 +18,7 @@
 package org.apache.poi.sl.usermodel;\r
 \r
 import java.awt.Color;\r
+import java.util.List;\r
 \r
 \r
 \r
@@ -339,4 +340,9 @@ public interface TextParagraph<
 \r
     \r
     TextShape<S,P> getParentShape();\r
+    \r
+    /**\r
+     * Fetch the text runs that are contained within this block of text\r
+     */\r
+    List<T> getTextRuns();\r
 }\r
index bd0164c275acc6d3737280b11a0c136c05a4055b..9eb27b616ed73d90f829155b8648ba87e91ff2e9 100644 (file)
@@ -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 <code>null</code> 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();
 }
index f487c108a40dc075f1aa0b6cc4ea7cee8eafe68c..0ec2ddfb91c6ac4c56d732e3035988a31342a58f 100644 (file)
@@ -26,7 +26,7 @@ public interface TextShape<
     /**\r
      * Vertical Text Types\r
      */\r
-    public enum TextDirection {\r
+    enum TextDirection {\r
         /**\r
          * Horizontal text. This should be default.\r
          */\r
@@ -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\r
      * </p>\r
      */\r
-    public enum TextAutofit {\r
+    enum TextAutofit {\r
         /**\r
          * Specifies that text within the text body should not be auto-fit to the bounding box.\r
          * Auto-fitting is when text within a text box is scaled in order to remain inside\r
@@ -89,6 +89,46 @@ public interface TextShape<
          */\r
         SHAPE\r
     }\r
+\r
+    /**\r
+     * This enum represents a compromise for the handling of\r
+     * HSLF run types (see org.apache.poi.hslf.record.TextHeaderAtom) and\r
+     * XSLF placeholders (see org.apache.poi.xslf.usermodel.Placeholder).\r
+     * When a shape is considered a placeholder by the generating application\r
+     * it can have special properties to alert the user that they may enter content into the shape.\r
+     * \r
+     * This enum and the handling around it may change significantly in future releases\r
+     */\r
+    enum TextPlaceholder {\r
+        /** Title placeholder shape text */\r
+        TITLE,\r
+        /** Body placeholder shape text */\r
+        BODY,\r
+        /** Center title placeholder shape text */\r
+        CENTER_TITLE,\r
+        /** Center body placeholder shape text */\r
+        CENTER_BODY,\r
+        /** Half-sized body placeholder shape text */\r
+        HALF_BODY,\r
+        /** Quarter-sized body placeholder shape text */\r
+        QUARTER_BODY,\r
+        /** Notes placeholder shape text */\r
+        NOTES,\r
+        /** Any other text */\r
+        OTHER\r
+    }\r
+\r
+    /**\r
+     * Sets (overwrites) the current text.\r
+     * Uses the properties of the first paragraph / textrun.\r
+     * Text paragraphs are split by \\r or \\n.\r
+     * New lines within text run are split by \\u000b\r
+     * \r
+     * @param text the text string used by this object.\r
+     * \r
+     * @return the last text run of the - potential split - text\r
+     */\r
+    TextRun setText(String text);\r
     \r
     /**\r
      * @return the TextParagraphs for this text box\r
@@ -99,6 +139,13 @@ public interface TextShape<
      * @return text shape margin\r
      */\r
     Insets2D getInsets();\r
+    \r
+    /**\r
+     * Sets the shape margins\r
+     *\r
+     * @param insets the new shape margins\r
+     */\r
+    void setInsets(Insets2D insets);\r
 \r
     /**\r
      * Compute the cumulative height occupied by the text\r
@@ -112,6 +159,14 @@ public interface TextShape<
      */\r
     VerticalAlignment getVerticalAlignment();\r
 \r
+    /**\r
+     * Sets the type of vertical alignment for the text.\r
+     *\r
+     * @param vAlign - the type of alignment.\r
+     * A {@code null} values unsets this property.\r
+     */\r
+    void setVerticalAlignment(VerticalAlignment vAlign);\r
+    \r
     /**\r
      * Returns if the text is centered.\r
      * If true and if the individual paragraph settings allow it,\r
@@ -122,13 +177,36 @@ public interface TextShape<
      */\r
     boolean isHorizontalCentered();\r
 \r
+    /**\r
+     * Sets if the paragraphs are horizontal centered\r
+     *\r
+     * @param isCentered true, if the paragraphs are horizontal centered\r
+     * A {@code null} values unsets this property.\r
+     */\r
+    void setHorizontalCentered(Boolean isCentered);\r
+    \r
     /**\r
      * @return whether to wrap words within the bounding rectangle\r
      */\r
     boolean getWordWrap();\r
 \r
+    /**\r
+     * @param wrap whether to wrap words within the bounding rectangle\r
+     */\r
+    void setWordWrap(boolean wrap);\r
+    \r
     /**\r
      * @return vertical orientation of the text\r
      */\r
     TextDirection getTextDirection();\r
+    \r
+    /**\r
+     * Sets the text placeholder\r
+     */\r
+    void setTextPlaceholder(TextPlaceholder placeholder);\r
+    \r
+    /**\r
+     * @return the text placeholder\r
+     */\r
+    TextPlaceholder getTextPlaceholder();\r
 }\r
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 (file)
index 087b28c..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*\r
- *  ====================================================================\r
- *    Licensed to the Apache Software Foundation (ASF) under one or more\r
- *    contributor license agreements.  See the NOTICE file distributed with\r
- *    this work for additional information regarding copyright ownership.\r
- *    The ASF licenses this file to You under the Apache License, Version 2.0\r
- *    (the "License"); you may not use this file except in compliance with\r
- *    the License.  You may obtain a copy of the License at\r
- *\r
- *        http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- *    Unless required by applicable law or agreed to in writing, software\r
- *    distributed under the License is distributed on an "AS IS" BASIS,\r
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- *    See the License for the specific language governing permissions and\r
- *    limitations under the License.\r
- * ====================================================================\r
- */\r
-package org.apache.poi.xslf.usermodel;\r
-\r
-/**\r
- * @author Yegor Kozlov\r
- */\r
-public enum Placeholder {\r
-    TITLE,\r
-    BODY,\r
-    CENTERED_TITLE,\r
-    SUBTITLE,\r
-    DATETIME,\r
-    SLIDE_NUMBER,\r
-    FOOTER,\r
-    HEADER,\r
-    CONTENT,\r
-    CHART,\r
-    TABLE,\r
-    CLIP_ART,\r
-    DGM,\r
-    MEDIA,\r
-    SLIDE_IMAGE,\r
-    PICTURE\r
-}\r
index e896420e9302c9c18a2a5e69d424f141bbf666b7..bd150811a2922574748628bf9e9ca019d3cea128 100644 (file)
@@ -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<XSLFShape,XSLFTextParagraph> {
         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<XSLFShape,XSLFTextParagraph> {
         return new Dimension((int)Units.toPoints(cx), (int)Units.toPoints(cy));
     }
 
-    /**
-     * Sets the page size to the given <code>Dimension</code> object.
-     *
-     * @param pgSize page size
-     */
+    @Override
     public void setPageSize(Dimension pgSize){
         CTSlideSize sz = CTSlideSize.Factory.newInstance();
         sz.setCx(Units.toEMU(pgSize.getWidth()));
index b9e40044887163583763f117e3df5cac18bc0bfc..e45df5ee29eb84258b91ad3476a23158b3a3b092 100644 (file)
@@ -25,7 +25,12 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;
 import org.openxmlformats.schemas.drawingml.x2006.main.CTPresetGeometry2D;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBodyProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.STShapeType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTShapeNonVisual;\r
 \r
@@ -71,14 +76,26 @@ public class XSLFAutoShape extends XSLFTextShape
         prst.addNewAvLst();\r
         return ct;\r
     }\r
+    \r
+    protected static void initTextBody(CTTextBody txBody) {\r
+        CTTextBodyProperties bodypr = txBody.addNewBodyPr();\r
+        bodypr.setAnchor(STTextAnchoringType.T);\r
+        bodypr.setRtlCol(false);\r
+        CTTextParagraph p = txBody.addNewP();\r
+        p.addNewPPr().setAlgn(STTextAlignType.L);\r
+        CTTextCharacterProperties endPr = p.addNewEndParaRPr();\r
+        endPr.setLang("en-US");\r
+        endPr.setSz(1100);   \r
+        p.addNewR().setT("");\r
+        txBody.addNewLstStyle();\r
+    }\r
 \r
     protected CTTextBody getTextBody(boolean create){\r
         CTShape shape = (CTShape)getXmlObject();\r
         CTTextBody txBody = shape.getTxBody();\r
         if (txBody == null && create) {\r
             txBody = shape.addNewTxBody();\r
-            txBody.addNewBodyPr();\r
-            txBody.addNewLstStyle();\r
+            initTextBody(txBody);\r
         }\r
         return txBody;\r
     }\r
index 37dbc33a227c57bda31e78bec62c900f01b4210f..dc1ef5af2c23b9bd8920c838944a30118b93258e 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.poi.sl.usermodel.PaintStyle;
 import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint;\r
 import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint;\r
 import org.apache.poi.sl.usermodel.PlaceableShape;\r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
 import org.apache.poi.sl.usermodel.Shape;\r
 import org.apache.poi.util.Beta;\r
 import org.apache.poi.util.Internal;\r
index f5d0207b78bf804c5ba0247b8850b7dfef49644e..daca97131d1a3fbc00e4b8f80e642b48ee48c50e 100644 (file)
@@ -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;
index 821cb07dff73691d08166d32d1a72cc9b8a818e3..28c98889cb054edf70229f30567228e4b2614dc8 100644 (file)
@@ -88,25 +88,23 @@ public abstract class XSLFSimpleShape extends XSLFShape
         super(shape,sheet);\r
     }\r
 \r
-    /**\r
-     *\r
-     * @param type\r
-     */\r
-    public void setShapeType(ShapeType type){\r
+    @Override\r
+    public void setShapeType(ShapeType type) {\r
         STShapeType.Enum geom = STShapeType.Enum.forInt(type.ooxmlId);\r
         getSpPr().getPrstGeom().setPrst(geom);\r
     }\r
 \r
+    @Override\r
     public ShapeType getShapeType(){\r
         STShapeType.Enum geom = getSpPr().getPrstGeom().getPrst();\r
         return ShapeType.forId(geom.intValue(), true);\r
     }\r
-    \r
+\r
     protected CTTransform2D getSafeXfrm() {\r
         CTTransform2D xfrm = getXfrm();\r
         return (xfrm == null ? getSpPr().addNewXfrm() : xfrm);\r
     }\r
-    \r
+\r
     protected CTTransform2D getXfrm() {\r
         PropertyFetcher<CTTransform2D> fetcher = new PropertyFetcher<CTTransform2D>() {\r
             public boolean fetch(XSLFShape shape) {\r
@@ -151,7 +149,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         ext.setCx(cx);\r
         ext.setCy(cy);\r
     }\r
-    \r
+\r
     @Override\r
     public void setRotation(double theta) {\r
         getSafeXfrm().setRot((int) (theta * 60000));\r
@@ -185,7 +183,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         return (xfrm == null || !xfrm.isSetFlipV()) ? false : getXfrm().getFlipV();\r
     }\r
 \r
-    \r
+\r
     /**\r
      * Get default line properties defined in the theme (if any).\r
      * Used internally to resolve shape properties.\r
@@ -199,7 +197,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         if (lnRef == null) return null;\r
         // 1-based index of a line style within the style matrix\r
         int idx = (int)lnRef.getIdx();\r
-        \r
+\r
         XSLFTheme theme = getSheet().getTheme();\r
         if (theme == null) return null;\r
         CTBaseStyles styles = theme.getXmlObject().getThemeElements();\r
@@ -208,7 +206,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         if (styleMatrix == null) return null;\r
         CTLineStyleList lineStyles = styleMatrix.getLnStyleLst();\r
         if (lineStyles == null || lineStyles.sizeOfLnArray() < idx) return null;\r
-        \r
+\r
         return lineStyles.getLnArray(idx - 1);\r
     }\r
 \r
@@ -262,7 +260,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
                         setValue(null); // use it as 'nofill' value\r
                         return true;\r
                     }\r
-                    \r
+\r
                     PaintStyle paint = null;\r
                     PackagePart pp = getSheet().getPackagePart();\r
                     for (XmlObject obj : spPr.selectPath("*")) {\r
@@ -290,11 +288,11 @@ public abstract class XSLFSimpleShape extends XSLFShape
 \r
         PaintStyle paint = fetcher.getValue();\r
         if (paint != null) return paint;\r
-        \r
+\r
         // line color was not found, check if it is defined in the theme\r
         CTShapeStyle style = getSpStyle();\r
         if (style == null) return null;\r
-        \r
+\r
         // get a reference to a line style within the style matrix.\r
         CTStyleMatrixReference lnRef = style.getLnRef();\r
         int idx = (int)lnRef.getIdx();\r
@@ -308,7 +306,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
 \r
         return paint;\r
     }\r
-    \r
+\r
     /**\r
      *\r
      * @param width line width in points. <code>0</code> means no line\r
@@ -362,6 +360,40 @@ public abstract class XSLFSimpleShape extends XSLFShape
         return lineWidth;\r
     }\r
 \r
+\r
+    /**\r
+     * @param compound set the line compound style\r
+     */\r
+    public void setLineCompound(LineCompound compound) {\r
+        CTShapeProperties spPr = getSpPr();\r
+        if (compound == null) {\r
+            if (spPr.isSetLn() && spPr.getLn().isSetCmpd())\r
+                spPr.getLn().unsetCmpd();\r
+        } else {\r
+            CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();\r
+            STCompoundLine.Enum xCmpd;\r
+            switch (compound) {\r
+                default:\r
+                case SINGLE:\r
+                    xCmpd = STCompoundLine.SNG;\r
+                    break;\r
+                case DOUBLE:\r
+                    xCmpd = STCompoundLine.DBL;\r
+                    break;\r
+                case THICK_THIN:\r
+                    xCmpd = STCompoundLine.THICK_THIN;\r
+                    break;\r
+                case THIN_THICK:\r
+                    xCmpd = STCompoundLine.THIN_THICK;\r
+                    break;\r
+                case TRIPLE:\r
+                    xCmpd = STCompoundLine.TRI;\r
+                    break;\r
+            }\r
+            ln.setCmpd(xCmpd);\r
+        }\r
+    }\r
+\r
     /**\r
      * @return the line compound\r
      */\r
@@ -392,7 +424,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
                 }\r
             }\r
         }\r
-        \r
+\r
         if (cmpd == null) return null;\r
 \r
         switch (cmpd) {\r
@@ -417,15 +449,12 @@ public abstract class XSLFSimpleShape extends XSLFShape
     public void setLineDash(LineDash dash) {\r
         CTShapeProperties spPr = getSpPr();\r
         if (dash == null) {\r
-            if (spPr.isSetLn() &&  spPr.getLn().isSetPrstDash())\r
+            if (spPr.isSetLn() && spPr.getLn().isSetPrstDash())\r
                 spPr.getLn().unsetPrstDash();\r
         } else {\r
-            CTPresetLineDashProperties val = CTPresetLineDashProperties.Factory\r
-                    .newInstance();\r
-            val.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));\r
-            CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr\r
-                    .addNewLn();\r
-            ln.setPrstDash(val);\r
+            CTLineProperties ln = spPr.isSetLn() ? spPr.getLn() : spPr.addNewLn();\r
+            CTPresetLineDashProperties ldp = ln.isSetPrstDash() ? ln.getPrstDash() : ln.addNewPrstDash();\r
+            ldp.setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));\r
         }\r
     }\r
 \r
@@ -513,13 +542,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         return cap;\r
     }\r
 \r
-    /**\r
-     * Specifies a solid color fill. The shape is filled entirely with the\r
-     * specified color.\r
-     *\r
-     * @param color the solid color fill. The value of <code>null</code> unsets\r
-     *              the solidFIll attribute from the underlying xml\r
-     */\r
+    @Override\r
     public void setFillColor(Color color) {\r
         CTShapeProperties spPr = getSpPr();\r
         if (color == null) {\r
@@ -545,10 +568,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         }\r
     }\r
 \r
-    /**\r
-     * @return solid fill color of null if not set or fill color\r
-     * is not solid (pattern or gradient)\r
-     */\r
+    @Override\r
     public Color getFillColor() {\r
         PaintStyle ps = getFillPaint();\r
         if (ps instanceof SolidPaint) {\r
@@ -615,7 +635,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
         }\r
         return geom;\r
     }\r
-    \r
+\r
     @Override\r
     void copy(XSLFShape sh){\r
         super.copy(sh);\r
@@ -635,7 +655,7 @@ public abstract class XSLFSimpleShape extends XSLFShape
             String relId = getSheet().importBlip(blipId, s.getSheet().getPackagePart());\r
             blip.setEmbed(relId);\r
         }\r
-        \r
+\r
         Color srcLineColor = s.getLineColor();\r
         Color tgtLineColor = getLineColor();\r
         if(srcLineColor != null && !srcLineColor.equals(tgtLineColor)) {\r
@@ -871,7 +891,31 @@ public abstract class XSLFSimpleShape extends XSLFShape
             public LineCompound getLineCompound() {\r
                 return XSLFSimpleShape.this.getLineCompound();\r
             }\r
-            \r
+\r
         };\r
     }\r
+\r
+    @Override\r
+    public void setStrokeStyle(Object... styles) {\r
+        if (styles.length == 0) {\r
+            // remove stroke\r
+            setLineColor(null);\r
+            return;\r
+        }\r
+        \r
+        // TODO: handle PaintStyle\r
+        for (Object st : styles) {\r
+            if (st instanceof Number) {\r
+                setLineWidth(((Number)st).doubleValue());\r
+            } else if (st instanceof LineCap) {\r
+                setLineCap((LineCap)st);\r
+            } else if (st instanceof LineDash) {\r
+                setLineDash((LineDash)st);\r
+            } else if (st instanceof LineCompound) {\r
+                setLineCompound((LineCompound)st);\r
+            } else if (st instanceof Color) {\r
+                setLineColor((Color)st);\r
+            }\r
+        }\r
+    }\r
 }\r
index cba6f3e6149c74490e881ac6eea006671a3a88ff..1d0d854bda38faaf96f200af3312d43cd5d8ee51 100644 (file)
@@ -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;
index c72819708389a597d62b53db2959ebb148d377e0..329ebf8994be885dd2c5cb44ec09b0f29e863679 100644 (file)
@@ -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;
index e6f37386b0cbe8fb4708a9aef6113b12abfbec1b..302e064b6a825da0c4d1353fe7538099766c774c 100644 (file)
@@ -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;
index 7469e25d42de72cf54afcd9975562d4cd827f8ed..b30b3ba269892d1b586beaca7081b06096079de5 100644 (file)
@@ -80,15 +80,22 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
         for(CTTableRow row : trArray) _rows.add(new XSLFTableRow(row, this));\r
     }\r
 \r
+    @Override\r
+    public XSLFTableCell getCell(int row, int col) {\r
+        return getRows().get(row).getCells().get(col);\r
+    }\r
+    \r
     @Internal\r
     public CTTable getCTTable(){\r
         return _table;\r
     }\r
 \r
+    @Override\r
     public int getNumberOfColumns() {\r
         return _table.getTblGrid().sizeOfGridColArray();\r
     }\r
 \r
+    @Override\r
     public int getNumberOfRows() {\r
         return _table.sizeOfTrArray();\r
     }\r
@@ -98,10 +105,16 @@ public class XSLFTable extends XSLFGraphicFrame implements Iterable<XSLFTableRow
                 _table.getTblGrid().getGridColArray(idx).getW());\r
     }\r
 \r
-    public void setColumnWidth(int idx, double width){\r
+    @Override\r
+    public void setColumnWidth(int idx, double width) {\r
         _table.getTblGrid().getGridColArray(idx).setW(Units.toEMU(width));\r
     }\r
 \r
+    @Override\r
+    public void setRowHeight(int row, double height) {\r
+        _table.getTrArray(row).setH(Units.toEMU(height));\r
+    }\r
+    \r
     public Iterator<XSLFTableRow> iterator(){\r
         return _rows.iterator();\r
     }\r
index 29f373929e3360e508986961c43794cc47945915..b5dcc8e0f5726909d802bf94aa911bd0a4e9bb4a 100644 (file)
@@ -21,6 +21,12 @@ package org.apache.poi.xslf.usermodel;
 \r
 import java.awt.Color;\r
 \r
+import org.apache.poi.sl.draw.DrawPaint;\r
+import org.apache.poi.sl.usermodel.PaintStyle;\r
+import org.apache.poi.sl.usermodel.StrokeStyle;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound;\r
+import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
 import org.apache.poi.sl.usermodel.TableCell;\r
 import org.apache.poi.sl.usermodel.VerticalAlignment;\r
 import org.apache.poi.util.Units;\r
@@ -44,7 +50,6 @@ import org.openxmlformats.schemas.drawingml.x2006.main.STTextAnchoringType;
  * Represents a cell of a table in a .pptx presentation\r
  */\r
 public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,XSLFTextParagraph> {\r
-    static double defaultBorderWidth = 1.0;\r
     private CTTableCellProperties _tcPr = null;\r
 \r
     /*package*/ XSLFTableCell(CTTableCell cell, XSLFSheet sheet){\r
@@ -57,8 +62,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         CTTextBody txBody = cell.getTxBody();\r
         if (txBody == null && create) {\r
             txBody = cell.addNewTxBody();\r
-            txBody.addNewBodyPr();\r
-            txBody.addNewLstStyle();\r
+            XSLFAutoShape.initTextBody(txBody);\r
         }\r
         return txBody;\r
     }\r
@@ -83,7 +87,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }\r
         return _tcPr;\r
     }\r
-    \r
+\r
     @Override\r
     public void setLeftInset(double margin){\r
         CTTableCellProperties pr = getCellProperties(true);\r
@@ -108,67 +112,174 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         pr.setMarB(Units.toEMU(margin));\r
     }\r
 \r
-    private CTLineProperties getCTLine(char bltr, boolean create) {\r
+    private CTLineProperties getCTLine(BorderEdge edge, boolean create) {\r
+        if (edge == null) {\r
+            throw new IllegalArgumentException("BorderEdge needs to be specified.");\r
+        }\r
+\r
         CTTableCellProperties pr = getCellProperties(create);\r
         if (pr == null) return null;\r
-        \r
-        switch (bltr) {\r
-            case 'b':\r
+\r
+        switch (edge) {\r
+            case bottom:\r
                 return (pr.isSetLnB()) ? pr.getLnB() : (create ? pr.addNewLnB() : null);\r
-            case 'l':\r
+            case left:\r
                 return (pr.isSetLnL()) ? pr.getLnL() : (create ? pr.addNewLnL() : null);\r
-            case 't':\r
+            case top:\r
                 return (pr.isSetLnT()) ? pr.getLnT() : (create ? pr.addNewLnT() : null);\r
-            case 'r':\r
+            case right:\r
                 return (pr.isSetLnR()) ? pr.getLnR() : (create ? pr.addNewLnR() : null);\r
             default:\r
                 return null;\r
         }\r
     }\r
+\r
+    @Override\r
+    public void removeBorder(BorderEdge edge) {\r
+        CTTableCellProperties pr = getCellProperties(false);\r
+        if (pr == null) return;\r
+        switch (edge) {\r
+            case bottom:\r
+                if (pr.isSetLnB()) {\r
+                    pr.unsetLnB();\r
+                }\r
+                break;\r
+            case left:\r
+                if (pr.isSetLnL()) {\r
+                    pr.unsetLnL();\r
+                }\r
+                break;\r
+            case top:\r
+                if (pr.isSetLnT()) {\r
+                    pr.unsetLnT();\r
+                }\r
+                break;\r
+            case right:\r
+                if (pr.isSetLnR()) {\r
+                    pr.unsetLnB();\r
+                }\r
+                break;\r
+            default:\r
+                throw new IllegalArgumentException();\r
+        }\r
+    }\r
+\r
+    @Override\r
+    public StrokeStyle getBorderStyle(final BorderEdge edge) {\r
+        final Double width = getBorderWidth(edge);\r
+        return (width == null) ? null : new StrokeStyle() {\r
+            public PaintStyle getPaint() {\r
+                return DrawPaint.createSolidPaint(getBorderColor(edge));\r
+            }\r
+\r
+            public LineCap getLineCap() {\r
+                return getBorderCap(edge);\r
+            }\r
+\r
+            public LineDash getLineDash() {\r
+                return getBorderDash(edge);\r
+            }\r
+\r
+            public LineCompound getLineCompound() {\r
+                return getBorderCompound(edge);\r
+            }\r
+\r
+            public double getLineWidth() {\r
+                return width;\r
+            }\r
+        };\r
+    }\r
     \r
-    private void setBorderWidth(char bltr, double width) {\r
-        CTLineProperties ln = getCTLine(bltr, true);\r
-        ln.setW(Units.toEMU(width));\r
+    @Override\r
+    public void setBorderStyle(BorderEdge edge, StrokeStyle style) {\r
+        if (style == null) {\r
+            throw new IllegalArgumentException("StrokeStyle needs to be specified.");\r
+        }\r
+        \r
+        LineCap cap = style.getLineCap();\r
+        if (cap != null) {\r
+            setBorderCap(edge, cap);\r
+        }\r
+        \r
+        LineCompound compound = style.getLineCompound();\r
+        if (compound != null) {\r
+            setBorderCompound(edge, compound);\r
+        }\r
+        \r
+        LineDash dash = style.getLineDash();\r
+        if (dash != null) {\r
+            setBorderDash(edge, dash);\r
+        }\r
+        \r
+        double width = style.getLineWidth();\r
+        setBorderWidth(edge, width);\r
     }\r
 \r
-    private double getBorderWidth(char bltr) {\r
-        CTLineProperties ln = getCTLine(bltr, false);\r
-        return (ln == null || !ln.isSetW()) ? defaultBorderWidth : Units.toPoints(ln.getW());\r
+    public Double getBorderWidth(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, false);\r
+        return (ln == null || !ln.isSetW()) ? null : Units.toPoints(ln.getW());\r
     }\r
 \r
-    private void setBorderColor(char bltr, Color color) {\r
-        CTLineProperties ln = getCTLine(bltr, true);\r
+    @Override\r
+    public void setBorderWidth(BorderEdge edge, double width) {\r
+        CTLineProperties ln = getCTLine(edge, true);\r
+        ln.setW(Units.toEMU(width));\r
+    }\r
 \r
-        if(color == null){\r
-            ln.addNewNoFill();\r
-            if(ln.isSetSolidFill()) ln.unsetSolidFill();\r
-        } else {\r
-            if(ln.isSetNoFill()) ln.unsetNoFill();\r
+    private CTLineProperties setBorderDefaults(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, true);\r
+        if (ln.isSetNoFill()) {\r
+            ln.unsetNoFill();\r
+        }\r
 \r
-            if(!ln.isSetPrstDash()) ln.addNewPrstDash().setVal(STPresetLineDashVal.SOLID);\r
+        if(!ln.isSetPrstDash()) {\r
+            ln.addNewPrstDash().setVal(STPresetLineDashVal.SOLID);\r
+        }\r
+        if (!ln.isSetCmpd()) {\r
             ln.setCmpd(STCompoundLine.SNG);\r
+        }\r
+        if (!ln.isSetAlgn()) {\r
             ln.setAlgn(STPenAlignment.CTR);\r
+        }\r
+        if (!ln.isSetCap()) {\r
             ln.setCap(STLineCap.FLAT);\r
+        }\r
+        if (!ln.isSetRound()) {\r
             ln.addNewRound();\r
+        }\r
 \r
+        if (!ln.isSetHeadEnd()) {\r
             CTLineEndProperties hd = ln.addNewHeadEnd();\r
             hd.setType(STLineEndType.NONE);\r
             hd.setW(STLineEndWidth.MED);\r
             hd.setLen(STLineEndLength.MED);\r
+        }\r
 \r
+        if (!ln.isSetTailEnd()) {\r
             CTLineEndProperties tl = ln.addNewTailEnd();\r
             tl.setType(STLineEndType.NONE);\r
             tl.setW(STLineEndWidth.MED);\r
             tl.setLen(STLineEndLength.MED);\r
+        }\r
 \r
-            CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
-            rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});\r
-            ln.addNewSolidFill().setSrgbClr(rgb);\r
+        return ln;\r
+    }\r
+\r
+    @Override\r
+    public void setBorderColor(BorderEdge edge, Color color) {\r
+        if (color == null) {\r
+            throw new IllegalArgumentException("Colors need to be specified.");\r
         }\r
-    }    \r
-    \r
-    private Color getBorderColor(char bltr) {\r
-        CTLineProperties ln = getCTLine(bltr,false);\r
+\r
+        CTLineProperties ln = setBorderDefaults(edge);\r
+\r
+        CTSRgbColor rgb = CTSRgbColor.Factory.newInstance();\r
+        rgb.setVal(new byte[]{(byte)color.getRed(), (byte)color.getGreen(), (byte)color.getBlue()});\r
+        ln.addNewSolidFill().setSrgbClr(rgb);\r
+    }\r
+\r
+    public Color getBorderColor(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, false);\r
         if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill()) return null;\r
 \r
         CTSolidColorFillProperties fill = ln.getSolidFill();\r
@@ -178,71 +289,65 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
         }\r
         byte[] val = fill.getSrgbClr().getVal();\r
         return new Color(0xFF & val[0], 0xFF & val[1], 0xFF & val[2]);\r
-    }    \r
-    \r
-    public void setBorderLeft(double width) {\r
-        setBorderWidth('l', width);\r
     }\r
 \r
-    public double getBorderLeft() {\r
-        return getBorderWidth('l');\r
-    }\r
-\r
-    public void setBorderLeftColor(Color color) {\r
-        setBorderColor('l', color);\r
-    }\r
-\r
-    public Color getBorderLeftColor() {\r
-        return getBorderColor('l');\r
-    }\r
+    public LineCompound getBorderCompound(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, false);\r
+        if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCmpd()) {\r
+            return null;\r
+        }\r
 \r
-    public void setBorderRight(double width) {\r
-        setBorderWidth('r', width);\r
+        return LineCompound.fromOoxmlId(ln.getCmpd().intValue());\r
     }\r
 \r
-    public double getBorderRight() {\r
-        return getBorderWidth('r');\r
-    }\r
+    @Override\r
+    public void setBorderCompound(BorderEdge edge, LineCompound compound) {\r
+        if (compound == null) {\r
+            throw new IllegalArgumentException("LineCompound need to be specified.");\r
+        }\r
 \r
-    public void setBorderRightColor(Color color) {\r
-        setBorderColor('r', color);\r
+        CTLineProperties ln = setBorderDefaults(edge);\r
+        ln.setCmpd(STCompoundLine.Enum.forInt(compound.ooxmlId));\r
     }\r
 \r
-    public Color getBorderRightColor() {\r
-        return getBorderColor('r');\r
-    }\r
+    public LineDash getBorderDash(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, false);\r
+        if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetPrstDash()) {\r
+            return null;\r
+        }\r
 \r
-    public void setBorderTop(double width) {\r
-        setBorderWidth('t', width);\r
+        return LineDash.fromOoxmlId(ln.getPrstDash().getVal().intValue());\r
     }\r
 \r
-    public double getBorderTop() {\r
-        return getBorderWidth('t');\r
-    }\r
+    @Override\r
+    public void setBorderDash(BorderEdge edge, LineDash dash) {\r
+        if (dash == null) {\r
+            throw new IllegalArgumentException("LineDash need to be specified.");\r
+        }\r
 \r
-    public void setBorderTopColor(Color color) {\r
-        setBorderColor('t', color);\r
+        CTLineProperties ln = setBorderDefaults(edge);\r
+        ln.getPrstDash().setVal(STPresetLineDashVal.Enum.forInt(dash.ooxmlId));\r
     }\r
 \r
-    public Color getBorderTopColor() {\r
-        return getBorderColor('t');\r
+    public LineCap getBorderCap(BorderEdge edge) {\r
+        CTLineProperties ln = getCTLine(edge, false);\r
+        if (ln == null || ln.isSetNoFill() || !ln.isSetSolidFill() || !ln.isSetCap()) {\r
+            return null;\r
+        }\r
+        \r
+        return LineCap.fromOoxmlId(ln.getCap().intValue());\r
     }\r
 \r
-    public void setBorderBottom(double width) {\r
-        setBorderWidth('b', width);\r
-    }\r
+    public void setBorderCap(BorderEdge edge, LineCap cap) {\r
+        if (cap == null) {\r
+            throw new IllegalArgumentException("LineCap need to be specified.");\r
+        }\r
 \r
-    public double getBorderBottom() {\r
-        return getBorderWidth('b');\r
+        CTLineProperties ln = setBorderDefaults(edge);\r
+        ln.setCap(STLineCap.Enum.forInt(cap.ooxmlId));\r
     }\r
 \r
-    public void setBorderBottomColor(Color color) {\r
-        setBorderColor('b', color);\r
-    }\r
 \r
-    public Color getBorderBottomColor(){\r
-        return getBorderColor('b');\r
-    }\r
 \r
     /**\r
      * Specifies a solid color fill. The shape is filled entirely with the specified color.\r
@@ -299,7 +404,7 @@ public class XSLFTableCell extends XSLFTextShape implements TableCell<XSLFShape,
     void setVMerge(boolean merge_) {\r
         ((CTTableCell)getXmlObject()).setVMerge(merge_);\r
     }\r
-    \r
+\r
     @Override\r
     public void setVerticalAlignment(VerticalAlignment anchor){\r
        CTTableCellProperties cellProps = getCellProperties(true);\r
index 65635c4d3c97accc8168187ee5a8b65229448fca..bb5bd42ae5771194e8566da9b848e62b92410ad5 100644 (file)
@@ -54,8 +54,7 @@ public class XSLFTextBox extends XSLFAutoShape
         prst.setPrst(STShapeType.RECT);\r
         prst.addNewAvLst();\r
         CTTextBody txBody = ct.addNewTxBody();\r
-        txBody.addNewBodyPr();\r
-        txBody.addNewLstStyle();\r
+        XSLFAutoShape.initTextBody(txBody);\r
 \r
         return ct;\r
     }\r
index 68d7438d4e3f5e38d784a2481e5f2ca677306701..cc12a634267d8f6c3298e464c942e28678aa9632 100644 (file)
@@ -32,7 +32,26 @@ import org.apache.poi.util.Units;
 import org.apache.poi.xslf.model.ParagraphPropertyFetcher;\r
 import org.apache.xmlbeans.XmlCursor;\r
 import org.apache.xmlbeans.XmlObject;\r
-import org.openxmlformats.schemas.drawingml.x2006.main.*;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.STTextFontAlignType;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;\r
 \r
@@ -100,6 +119,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
 \r
     }\r
 \r
+    @Override\r
     public List<XSLFTextRun> getTextRuns(){\r
         return _runs;\r
     }\r
index fd0f44d75ac7ca7f5bfeafe160cdf9a928114f60..8ce7c5241e9b0238020e3915d9e7372ae605e399 100644 (file)
@@ -206,12 +206,7 @@ public class XSLFTextRun implements TextRun {
         }\r
     }\r
 \r
-    /**\r
-     * Specifies the typeface, or name of the font that is to be used for this text run.\r
-     *\r
-     * @param typeface  the font to apply to this text run.\r
-     * The value of <code>null</code> unsets the Typeface attrubute from the underlying xml.\r
-     */\r
+    @Override\r
     public void setFontFamily(String typeface){\r
         setFontFamily(typeface, (byte)-1, (byte)-1, false);\r
     }\r
@@ -236,9 +231,7 @@ public class XSLFTextRun implements TextRun {
         }\r
     }\r
 \r
-    /**\r
-     * @return  font family or null if not set\r
-     */\r
+    @Override\r
     public String getFontFamily(){\r
         final XSLFTheme theme = _p.getParentShape().getSheet().getTheme();\r
 \r
@@ -281,18 +274,12 @@ public class XSLFTextRun implements TextRun {
         return  visitor.getValue() == null ? 0 : visitor.getValue();\r
     }\r
 \r
-    /**\r
-     * Specifies whether a run of text will be formatted as strikethrough text.\r
-     *\r
-     * @param strike whether a run of text will be formatted as strikethrough text.\r
-     */\r
+    @Override\r
     public void setStrikethrough(boolean strike) {\r
         getRPr().setStrike(strike ? STTextStrikeType.SNG_STRIKE : STTextStrikeType.NO_STRIKE);\r
     }\r
 \r
-    /**\r
-     * @return whether a run of text will be formatted as strikethrough text. Default is false.\r
-     */\r
+    @Override\r
     public boolean isStrikethrough() {\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -307,9 +294,7 @@ public class XSLFTextRun implements TextRun {
         return fetcher.getValue() == null ? false : fetcher.getValue();\r
     }\r
 \r
-    /**\r
-     * @return whether a run of text will be formatted as a superscript text. Default is false.\r
-     */\r
+    @Override\r
     public boolean isSuperscript() {\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -357,9 +342,7 @@ public class XSLFTextRun implements TextRun {
         setBaselineOffset(flag ? -25.0 : 0.);\r
     }\r
 \r
-    /**\r
-     * @return whether a run of text will be formatted as a superscript text. Default is false.\r
-     */\r
+    @Override\r
     public boolean isSubscript() {\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -392,18 +375,12 @@ public class XSLFTextRun implements TextRun {
         return fetcher.getValue() == null ? TextCap.NONE : fetcher.getValue();\r
     }\r
 \r
-    /**\r
-     * Specifies whether this run of text will be formatted as bold text\r
-     *\r
-     * @param bold whether this run of text will be formatted as bold text\r
-     */\r
+    @Override\r
     public void setBold(boolean bold){\r
         getRPr().setB(bold);\r
     }\r
 \r
-    /**\r
-     * @return whether this run of text is formatted as bold text\r
-     */\r
+    @Override\r
     public boolean isBold(){\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -418,16 +395,12 @@ public class XSLFTextRun implements TextRun {
         return fetcher.getValue() == null ? false : fetcher.getValue();\r
     }\r
 \r
-    /**\r
-     * @param italic whether this run of text is formatted as italic text\r
-     */\r
+    @Override\r
     public void setItalic(boolean italic){\r
         getRPr().setI(italic);\r
     }\r
 \r
-    /**\r
-     * @return whether this run of text is formatted as italic text\r
-     */\r
+    @Override\r
     public boolean isItalic(){\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -442,16 +415,12 @@ public class XSLFTextRun implements TextRun {
         return fetcher.getValue() == null ? false : fetcher.getValue();\r
     }\r
 \r
-    /**\r
-     * @param underline whether this run of text is formatted as underlined text\r
-     */\r
-    public void setUnderline(boolean underline) {\r
+    @Override\r
+    public void setUnderlined(boolean underline) {\r
         getRPr().setU(underline ? STTextUnderlineType.SNG : STTextUnderlineType.NONE);\r
     }\r
 \r
-    /**\r
-     * @return whether this run of text is formatted as underlined text\r
-     */\r
+    @Override\r
     public boolean isUnderlined(){\r
         CharacterPropertyFetcher<Boolean> fetcher = new CharacterPropertyFetcher<Boolean>(_p.getIndentLevel()){\r
             public boolean fetch(CTTextCharacterProperties props){\r
@@ -501,6 +470,7 @@ public class XSLFTextRun implements TextRun {
         CTPlaceholder ph = shape.getCTPlaceholder();\r
         if (ph == null){\r
             // if it is a plain text box then take defaults from presentation.xml\r
+            @SuppressWarnings("resource")\r
             XMLSlideShow ppt = sheet.getSlideShow();\r
             CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(_p.getIndentLevel());\r
             if (themeProps != null) {\r
@@ -543,7 +513,7 @@ public class XSLFTextRun implements TextRun {
         if(italic != isItalic()) setItalic(italic);\r
 \r
         boolean underline = r.isUnderlined();\r
-        if(underline != isUnderlined()) setUnderline(underline);\r
+        if(underline != isUnderlined()) setUnderlined(underline);\r
 \r
         boolean strike = r.isStrikethrough();\r
         if(strike != isStrikethrough()) setStrikethrough(strike);\r
index 8cc90f979f0738570cbd692e59af153be6808c8d..8a4a935209220df156084a1d0977683c4e4e0d09 100644 (file)
@@ -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<VerticalAlignment> fetcher = new TextBodyPropertyFetcher<VerticalAlignment>(){
             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<Boolean> fetcher = new TextBodyPropertyFetcher<Boolean>(){
             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
index 3350149751c28e16d73257db5c70c2b767e07e0f..525f55ef7b3fcb756cef43a3b266b6f289937d16 100644 (file)
@@ -268,7 +268,7 @@ public class TestXSLFAutoShape {
 \r
         assertFalse(r.isUnderlined());\r
         assertFalse(r.getXmlObject().getRPr().isSetU());\r
-        r.setUnderline(true);\r
+        r.setUnderlined(true);\r
         assertTrue(r.isUnderlined());\r
         assertEquals(STTextUnderlineType.SNG, r.getXmlObject().getRPr().getU());\r
 \r
index 0eb075acafd1a8a3203441cb0fa25bb05a9cb657..02fac93bc864b44a3d4b3801f9ddf017f1681316 100644 (file)
@@ -20,13 +20,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;\r
 import static org.junit.Assert.assertNull;\r
 \r
+import java.io.IOException;\r
+\r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
 import org.apache.poi.xslf.XSLFTestDataSamples;\r
 import org.junit.Test;\r
 \r
 public class TestXSLFNotes {\r
 \r
     @Test\r
-    public void createNewNote() {\r
+    public void createNewNote() throws IOException {\r
 \r
         XMLSlideShow ppt = new XMLSlideShow();\r
         XSLFSlide slide1 = ppt.createSlide();\r
@@ -48,10 +51,12 @@ public class TestXSLFNotes {
         }\r
         assertNotNull(note);\r
         assertEquals("New Note", note);\r
+        \r
+        ppt.close();\r
     }\r
 \r
     @Test\r
-    public void addNote() {\r
+    public void addNote() throws IOException {\r
 \r
         XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx");\r
 \r
@@ -69,10 +74,12 @@ public class TestXSLFNotes {
         }\r
         assertNotNull(note);\r
         assertEquals("New Note", note);\r
+        \r
+        ppt.close();\r
     }\r
 \r
     @Test\r
-    public void replaceNotes() {\r
+    public void replaceNotes() throws IOException {\r
 \r
         XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("sample.pptx");\r
 \r
@@ -93,5 +100,7 @@ public class TestXSLFNotes {
             assertNotNull(note);\r
             assertEquals("New Note", note);\r
         }\r
+        \r
+        ppt.close();\r
     }\r
 }\r
index db2c9833f7b468dcf23b3750b16721cab47d2be2..452f22ebcb6f6a38262e8fbbd3e401c3b8eec651 100644 (file)
@@ -28,6 +28,7 @@ import java.io.IOException;
 import java.util.List;\r
 \r
 import org.apache.poi.sl.draw.geom.TestPresetGeometries;\r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
 import org.apache.poi.sl.usermodel.StrokeStyle.LineCap;\r
 import org.apache.poi.sl.usermodel.StrokeStyle.LineDash;\r
 import org.apache.poi.util.Units;\r
@@ -168,7 +169,7 @@ public class TestXSLFSimpleShape {
     }\r
 \r
     @Test\r
-    public void testDefaultProperties() {\r
+    public void testDefaultProperties() throws IOException {\r
         XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");\r
 \r
         XSLFSlide slide6 = ppt.getSlides().get(5);\r
@@ -234,10 +235,12 @@ public class TestXSLFSimpleShape {
         assertEquals(50000, ref5.getLumModArray(0).getVal());\r
         assertEquals("accent1", ref5.getVal().toString());\r
         assertEquals(new Color(79, 129, 189), s5.getFillColor());\r
+        \r
+        ppt.close();\r
     }\r
 \r
     @Test\r
-    public void testAnchor(){\r
+    public void testAnchor() throws IOException {\r
         XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");\r
         List<XSLFSlide> slide = ppt.getSlides();\r
 \r
@@ -267,6 +270,7 @@ public class TestXSLFSimpleShape {
         assertNotNull(layout5.getSlideMaster().getTextShapeByType(Placeholder.TITLE).getSpPr().getXfrm());\r
         assertEquals(shTitle.getAnchor(), layout5.getSlideMaster().getTextShapeByType(Placeholder.TITLE).getAnchor());\r
 \r
+        ppt.close();\r
     }\r
 \r
     @SuppressWarnings({ "deprecation", "unused" })\r
index 3b7c5cbcc219bca3e57628209cc237da126d58cf..cf535b5650f417412d011a0fb52c543e7d6946a2 100644 (file)
 ==================================================================== */\r
 package org.apache.poi.xslf.usermodel;\r
 \r
-import static org.junit.Assert.*;\r
+import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertNotNull;\r
+import static org.junit.Assert.assertNull;\r
+import static org.junit.Assert.assertSame;\r
+import static org.junit.Assert.assertTrue;\r
 \r
+import java.awt.Color;\r
+import java.io.IOException;\r
+import java.util.List;\r
+\r
+import org.apache.poi.sl.usermodel.TableCell.BorderEdge;\r
 import org.apache.poi.sl.usermodel.VerticalAlignment;\r
 import org.apache.poi.xslf.XSLFTestDataSamples;\r
 import org.junit.Test;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell;\r
 import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame;\r
 \r
-import java.awt.Color;\r
-import java.util.List;\r
-\r
 /**\r
  * @author Yegor Kozlov\r
  */\r
 public class TestXSLFTable {\r
     @Test\r
-    public void testRead(){\r
+    public void testRead() throws IOException {\r
         XMLSlideShow  ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx");\r
 \r
         XSLFSlide slide = ppt.getSlides().get(3);\r
@@ -69,10 +75,12 @@ public class TestXSLFTable {
         assertEquals("A1", cells1.get(0).getText());\r
         assertEquals("B1", cells1.get(1).getText());\r
         assertEquals("C1", cells1.get(2).getText());\r
+        \r
+        ppt.close();\r
     }\r
 \r
     @Test\r
-    public void testCreate() {\r
+    public void testCreate() throws IOException {\r
         XMLSlideShow ppt = new XMLSlideShow();\r
         XSLFSlide slide = ppt.createSlide();\r
 \r
@@ -121,38 +129,21 @@ public class TestXSLFTable {
         cell1.addNewTextParagraph().addNewTextRun().setText("Apache");\r
         assertEquals("Apache", cell1.getText());\r
 \r
-        assertEquals(1.0, cell1.getBorderBottom(), 0);\r
-        cell1.setBorderBottom(2.0);\r
-        assertEquals(2.0, cell1.getBorderBottom(), 0);\r
-        assertNull(cell1.getBorderBottomColor());\r
-        cell1.setBorderBottomColor(Color.yellow);\r
-        assertEquals(Color.yellow, cell1.getBorderBottomColor());\r
-\r
-        assertEquals(1.0, cell1.getBorderTop(), 0);\r
-        cell1.setBorderTop(2.0);\r
-        assertEquals(2.0, cell1.getBorderTop(), 0);\r
-        assertNull(cell1.getBorderTopColor());\r
-        cell1.setBorderTopColor(Color.yellow);\r
-        assertEquals(Color.yellow, cell1.getBorderTopColor());\r
-\r
-        assertEquals(1.0, cell1.getBorderLeft(), 0);\r
-        cell1.setBorderLeft(2.0);\r
-        assertEquals(2.0, cell1.getBorderLeft(), 0);\r
-        assertNull(cell1.getBorderLeftColor());\r
-        cell1.setBorderLeftColor(Color.yellow);\r
-        assertEquals(Color.yellow, cell1.getBorderLeftColor());\r
-\r
-        assertEquals(1.0, cell1.getBorderRight(), 0);\r
-        cell1.setBorderRight(2.0);\r
-        assertEquals(2.0, cell1.getBorderRight(), 0);\r
-        assertNull(cell1.getBorderRightColor());\r
-        cell1.setBorderRightColor(Color.yellow);\r
-        assertEquals(Color.yellow, cell1.getBorderRightColor());\r
+        for (BorderEdge edge : BorderEdge.values()) {\r
+            assertNull(cell1.getBorderWidth(edge));\r
+            cell1.setBorderWidth(edge, 2.0);\r
+            assertEquals(2.0, cell1.getBorderWidth(edge), 0);\r
+            assertNull(cell1.getBorderColor(edge));\r
+            cell1.setBorderColor(edge, Color.yellow);\r
+            assertEquals(Color.yellow, cell1.getBorderColor(edge));\r
+        }\r
 \r
         assertEquals(VerticalAlignment.TOP, cell1.getVerticalAlignment());\r
         cell1.setVerticalAlignment(VerticalAlignment.MIDDLE);\r
         assertEquals(VerticalAlignment.MIDDLE, cell1.getVerticalAlignment());\r
         cell1.setVerticalAlignment(null);\r
         assertEquals(VerticalAlignment.TOP, cell1.getVerticalAlignment());\r
+        \r
+        ppt.close();\r
     }\r
 }
\ No newline at end of file
index 59b0dca95c12e50b65245d07361211f69f046fdf..cee11e541ad6f168d24fa883f58a998d64c509b3 100644 (file)
@@ -19,6 +19,9 @@ package org.apache.poi.xslf.usermodel;
 import static org.junit.Assert.assertEquals;\r
 import static org.junit.Assert.assertNull;\r
 \r
+import java.io.IOException;\r
+\r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
 import org.junit.Test;\r
 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;\r
 \r
@@ -28,7 +31,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties
 public class TestXSLFTextBox {\r
 \r
     @Test\r
-    public void testPlaceholder() {\r
+    public void testPlaceholder() throws IOException {\r
         XMLSlideShow ppt = new XMLSlideShow();\r
         XSLFSlide slide = ppt.createSlide();\r
 \r
@@ -39,13 +42,15 @@ public class TestXSLFTextBox {
         shape.setPlaceholder(null);\r
         assertNull(shape.getTextType());\r
         shape.setText("Apache POI");\r
+        \r
+        ppt.close();\r
     }\r
 \r
     /**\r
      * text box inherits default text proeprties from presentation.xml\r
      */\r
     @Test\r
-    public void testDefaultTextStyle() {\r
+    public void testDefaultTextStyle() throws IOException {\r
         XMLSlideShow ppt = new XMLSlideShow();\r
         XSLFSlide slide = ppt.createSlide();\r
 \r
@@ -79,5 +84,7 @@ public class TestXSLFTextBox {
 \r
         pPr.unsetSz();  // Should never be\r
         assertNull(r.getFontSize());\r
+        \r
+        ppt.close();\r
     }\r
 }
\ No newline at end of file
index e0c4f9dd96305af6cf29dbef3814f2affff162cd..18632ffbf0857dff8717c4acc2843d719b21783c 100644 (file)
@@ -28,6 +28,7 @@ import java.awt.Color;
 import java.io.IOException;\r
 import java.util.List;\r
 \r
+import org.apache.poi.sl.usermodel.SimpleShape.Placeholder;\r
 import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;\r
 import org.apache.poi.sl.usermodel.VerticalAlignment;\r
 import org.apache.poi.xslf.XSLFTestDataSamples;\r
@@ -45,7 +46,7 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
 public class TestXSLFTextShape {\r
 \r
     @Test\r
-    public void testLayouts(){\r
+    public void testLayouts() throws IOException {\r
         XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx");\r
 \r
         List<XSLFSlide> slide = ppt.getSlides();\r
@@ -57,6 +58,8 @@ public class TestXSLFTextShape {
         verifySlide7(slide.get(6));\r
         verifySlide8(slide.get(7));\r
         verifySlide10(slide.get(9));\r
+        \r
+        ppt.close();\r
     }\r
 \r
     void verifySlide1(XSLFSlide slide){\r
index 834dea5ff0e329b04fe0edeecbb99218e223f171..0022822b826281f464522bf1d45423972ce17995 100644 (file)
@@ -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 (file)
index 1e632b8..0000000
+++ /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<HSLFShape,HSLFTextParagraph> parent){
-        super(escherRecord, parent);
-    }
-
-    public Placeholder(ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
-        super(parent);
-    }
-
-    public Placeholder(){
-        super();
-    }
-
-    /**
-     * Create a new Placeholder and initialize internal structures
-     *
-     * @return the created <code>EscherContainerRecord</code> 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;
-    }
-}
index 21c07010ca86bb326a344c3b3c7fd40277b2f4fe..329f78f42381660d70f8b7614fa1b7b773f1e784 100644 (file)
@@ -67,7 +67,7 @@ public class HSLFAutoShape extends HSLFTextShape implements AutoShape<HSLFShape,
     protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){
         setVerticalAlignment(VerticalAlignment.MIDDLE);
         setHorizontalCentered(true);
-        setWordWrap(HSLFTextBox.WrapNone);
+        setWordWrap(false);
     }
 
     /**
index 22317fb62ad0c571020184f69286d8d5776553d4..bbfe93f97ca613a0681dcfd0563b1e780336c550 100644 (file)
@@ -43,7 +43,6 @@ import org.apache.poi.util.Units;
  */
 public class HSLFGroupShape extends HSLFShape
 implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
-
     /**
       * Create a new ShapeGroup. This constructor is used when a new shape is created.
       *
@@ -73,34 +72,16 @@ implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
         spgr.setRectY1(y1);
         spgr.setRectX2(x2);
         spgr.setRectY2(y2);
-
     }
 
     @Override
@@ -129,6 +109,27 @@ implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
         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 <code>EscherSpgrContainer</code> which represents a group of shapes
      */
@@ -174,23 +175,22 @@ implements HSLFShapeContainer, GroupShape<HSLFShape,HSLFTextParagraph> {
     }
 
     /**
-     * Moves this <code>ShapeGroup</code> to the specified location.
-     * <p>
-     * @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 <code>ShapeGroup</code> 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<HSLFShape,HSLFTextParagraph> {
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * @return the shapes contained in this group container
-     */
     @Override
     public List<HSLFShape> 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 (file)
index 0000000..c0a7aef
--- /dev/null
@@ -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<HSLFShape,HSLFTextParagraph> parent){
+        super(escherRecord, parent);
+    }
+
+    public HSLFPlaceholder(ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
+        super(parent);
+    }
+
+    public HSLFPlaceholder(){
+        super();
+    }
+
+    /**
+     * Create a new Placeholder and initialize internal structures
+     *
+     * @return the created <code>EscherContainerRecord</code> which holds shape data
+     */
+    protected EscherContainerRecord createSpContainer(boolean isChild){
+        _escherContainer = super.createSpContainer(isChild);
+        
+        setPlaceholder(Placeholder.BODY);
+
+        return _escherContainer;
+    }
+}
index 85f3a906ea4161e78b465565498b4500317d1379..81679c02df2b6b9d04e2e31dd911ce3b26b1fc5a 100644 (file)
@@ -116,19 +116,11 @@ public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
      * @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);
index f2aac4da252274b9ae3472744f1a812128d89429..4fe197782e26bdbfec4a7dbd042afa9a27b4cf12 100644 (file)
@@ -56,7 +56,7 @@ public final class HSLFShapeFactory {
             EscherPropertyFactory f = new EscherPropertyFactory();
             List<EscherProperty> 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<HSLFShape,HSLFTextParagraph> 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<HSLFShape,HSLFTextParagraph> 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 extends Record> T getClientDataRecord(EscherContainerRecord spContainer, int recordType) {
-        Record oep = null;
         for (Iterator<EscherRecord> 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;
     }
 
 }
index 139840c548704f96dd551764cde8a1da36b7ef6b..1a46a5e1755bb145ed143ab6be0a73b4320508a7 100644 (file)
@@ -458,7 +458,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
             throw new IllegalArgumentException("numRows and numCols must be greater than 0");
         }
         HSLFTable s = new HSLFTable(numRows,numCols);
-        s.setAnchor(new Rectangle(0, 0, 100, 100));
+        // anchor is set in constructor based on numRows/numCols
         addShape(s);
         return s;
     }
index d75aebf0077c8f1129ebe8c890f6236b265dad81..74761e49ca93c9710e7f91f0d2cc8ab8d6c0e448 100644 (file)
@@ -27,6 +27,7 @@ import org.apache.poi.sl.draw.DrawPaint;
 import org.apache.poi.sl.draw.geom.*;
 import org.apache.poi.sl.usermodel.*;
 import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
+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.util.LittleEndian;
@@ -146,12 +147,33 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         return clr == null ? Color.black : clr;
     }
 
+    /**
+     * Gets line cap.
+     *
+     * @return cap of the line.
+     */
+    public LineCap getLineCap(){
+        AbstractEscherOptRecord opt = getEscherOptRecord();
+        EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDCAPSTYLE);
+        return (prop == null) ? LineCap.FLAT : LineCap.fromNativeId(prop.getPropertyValue());
+    }
+
+    /**
+     * Sets line cap.
+     *
+     * @param pen new style of the line.
+     */
+    public void setLineCap(LineCap pen){
+        AbstractEscherOptRecord opt = getEscherOptRecord();
+        setEscherProperty(opt, EscherProperties.LINESTYLE__LINEENDCAPSTYLE, pen == LineCap.FLAT ? -1 : pen.nativeId);
+    }
+    
     /**
      * Gets line dashing.
      *
      * @return dashing of the line.
      */
-    public LineDash getLineDashing(){
+    public LineDash getLineDash(){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING);
         return (prop == null) ? LineDash.SOLID : LineDash.fromNativeId(prop.getPropertyValue());
@@ -162,7 +184,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
      *
      * @param pen new style of the line.
      */
-    public void setLineDashing(LineDash pen){
+    public void setLineDash(LineDash pen){
         AbstractEscherOptRecord opt = getEscherOptRecord();
         setEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING, pen == LineDash.SOLID ? -1 : pen.nativeId);
     }
@@ -177,7 +199,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE);
         return (prop == null) ? LineCompound.SINGLE : LineCompound.fromNativeId(prop.getPropertyValue());
     }
-    
+
     /**
      * Sets the line compound style
      *
@@ -204,7 +226,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             }
 
             public LineDash getLineDash() {
-                return HSLFSimpleShape.this.getLineDashing();
+                return HSLFSimpleShape.this.getLineDash();
             }
 
             public LineCompound getLineCompound() {
@@ -214,23 +236,17 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             public double getLineWidth() {
                 return HSLFSimpleShape.this.getLineWidth();
             }
-            
+
         };
     }
 
-    /**
-     * The color used to fill this shape.
-     */
-    public Color getFillColor(){
+    @Override
+    public Color getFillColor() {
         return getFill().getForegroundColor();
     }
 
-    /**
-     * The color used to fill this shape.
-     *
-     * @param color the background color
-     */
-    public void setFillColor(Color color){
+    @Override
+    public void setFillColor(Color color) {
         getFill().setForegroundColor(color);
     }
 
@@ -353,10 +369,10 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         if (name == null || !name.matches("adj([1-9]|10)?")) {
             throw new IllegalArgumentException("Adjust value '"+name+"' not supported.");
         }
-        
+
         name = name.replace("adj", "");
         if ("".equals(name)) name = "1";
-        
+
         short escherProp;
         switch (Integer.parseInt(name)) {
             case 1: escherProp = EscherProperties.GEOMETRY__ADJUSTVALUE; break;
@@ -371,7 +387,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             case 10: escherProp = EscherProperties.GEOMETRY__ADJUST10VALUE; break;
             default: throw new RuntimeException();
         }
-        
+
         int adjval = getEscherProperty(escherProp, -1);
         return (adjval == -1) ? null : new Guide(name, "val "+adjval);
     }
@@ -386,7 +402,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             logger.log(POILogger.WARN, "No preset shape definition for shapeType: "+name);
             return null;
         }
-        
+
         return geom;
     }
 
@@ -399,7 +415,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
         int offY = (prop == null) ? 0 : prop.getPropertyValue();
         return Math.toDegrees(Math.atan2(offY, offX));
     }
-    
+
     public double getShadowDistance() {
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.SHADOWSTYLE__OFFSETX);
@@ -415,13 +431,13 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
     public Color getShadowColor(){
         Color clr = getColor(EscherProperties.SHADOWSTYLE__COLOR, EscherProperties.SHADOWSTYLE__OPACITY, -1);
         return clr == null ? Color.black : clr;
-    }    
-    
+    }
+
     public Shadow<HSLFShape,HSLFTextParagraph> getShadow() {
         AbstractEscherOptRecord opt = getEscherOptRecord();
         EscherProperty shadowType = opt.lookup(EscherProperties.SHADOWSTYLE__TYPE);
         if (shadowType == null) return null;
-        
+
         return new Shadow<HSLFShape,HSLFTextParagraph>(){
             public SimpleShape<HSLFShape,HSLFTextParagraph> getShadowParent() {
                 return HSLFSimpleShape.this;
@@ -443,7 +459,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             public SolidPaint getFillStyle() {
                 return DrawPaint.createSolidPaint(getShadowColor());
             }
-            
+
         };
     }
 
@@ -475,4 +491,123 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
             }
         };
     }
-}
+
+    protected void setPlaceholder(Placeholder placeholder) {
+        EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
+        int flags = spRecord.getFlags();
+        flags |= EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HAVEMASTER;
+        spRecord.setFlags(flags);
+
+        EscherClientDataRecord cldata = _escherContainer.getChildById(EscherClientDataRecord.RECORD_ID);
+        if (cldata == null) {
+            cldata = new EscherClientDataRecord();
+            // append placeholder container before EscherTextboxRecord
+            _escherContainer.addChildBefore(cldata, EscherTextboxRecord.RECORD_ID);
+        }
+        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);
+
+        boolean isMaster = (getSheet() instanceof HSLFSlideMaster);
+        boolean isNotes = (getSheet() instanceof HSLFNotes);
+        byte phId;
+        switch (placeholder) {
+            case TITLE:
+                phId = (isMaster) ? OEPlaceholderAtom.MasterTitle : OEPlaceholderAtom.Title;
+                break;
+            case BODY:
+                phId = (isMaster) ? OEPlaceholderAtom.MasterBody :
+                    ((isNotes) ? OEPlaceholderAtom.NotesBody : OEPlaceholderAtom.Body);
+                break;
+            case CENTERED_TITLE:
+                phId = (isMaster) ? OEPlaceholderAtom.MasterCenteredTitle : OEPlaceholderAtom.CenteredTitle;
+                break;
+            case SUBTITLE:
+                phId = (isMaster) ? OEPlaceholderAtom.MasterSubTitle : OEPlaceholderAtom.Subtitle;
+                break;
+            case DATETIME:
+                phId = OEPlaceholderAtom.MasterDate;
+                break;
+            case SLIDE_NUMBER:
+                phId = OEPlaceholderAtom.MasterSlideNumber;
+                break;
+            case FOOTER:
+                phId = OEPlaceholderAtom.MasterFooter;
+                break;
+            case HEADER:
+                phId = OEPlaceholderAtom.MasterHeader;
+                break;
+            case DGM:
+            case CHART:
+                phId = OEPlaceholderAtom.Graph;
+                break;
+            case TABLE:
+                phId = OEPlaceholderAtom.Table;
+                break;
+            case PICTURE:
+            case CLIP_ART:
+                phId = OEPlaceholderAtom.ClipArt;
+                break;
+            case MEDIA:
+                phId = OEPlaceholderAtom.MediaClip;
+                break;
+            case SLIDE_IMAGE:
+                phId = (isMaster) ? OEPlaceholderAtom.MasterNotesSlideImage : OEPlaceholderAtom.NotesSlideImage;
+                break;
+            default:
+            case CONTENT:
+                phId = OEPlaceholderAtom.Object;
+                break;
+        }
+        oep.setPlaceholderId(phId);
+
+        //convert hslf into ddf record
+        ByteArrayOutputStream out = new ByteArrayOutputStream();
+        try {
+            oep.writeOut(out);
+        } catch(Exception e){
+            throw new HSLFException(e);
+        }
+        cldata.setRemainingData(out.toByteArray());
+    }
+
+
+    @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);
+            }
+        }
+    }
+}
\ No newline at end of file
index b4dd77144f69d90b5f3c666c8503ffef8be374b7..8e94421c5d9386ab31587cc7f00901390b3bb2c0 100644 (file)
@@ -27,7 +27,6 @@ import org.apache.poi.ddf.EscherDggRecord;
 import org.apache.poi.ddf.EscherSpRecord;
 import org.apache.poi.hslf.model.Comment;
 import org.apache.poi.hslf.model.HeadersFooters;
-import org.apache.poi.hslf.model.Placeholder;
 import org.apache.poi.hslf.record.ColorSchemeAtom;
 import org.apache.poi.hslf.record.Comment2000;
 import org.apache.poi.hslf.record.EscherTextboxWrapper;
@@ -196,7 +195,7 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
         * @return <code>TextBox</code> 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");
index 7064a862bf79344d1d14cebe94bbf6fd971d2ab9..46a356fec9aff94138942fc43cbf4eac693d4ca6 100644 (file)
@@ -531,9 +531,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
                return HSLFSoundData.find(_documentRecord);
        }
 
-       /**
-        * Return the current page size
-        */
+       @Override
        public Dimension getPageSize() {
                DocumentAtom docatom = _documentRecord.getDocumentAtom();
                int pgx = (int)Units.masterToPoints((int)docatom.getSlideSizeX());
@@ -541,12 +539,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
                return new Dimension(pgx, pgy);
        }
 
-       /**
-        * Change the current page size
-        *
-        * @param pgsize
-        *            page size (in points)
-        */
+       @Override
        public void setPageSize(Dimension pgsize) {
                DocumentAtom docatom = _documentRecord.getDocumentAtom();
                docatom.setSlideSizeX(Units.pointsToMaster(pgsize.width));
index 2f785c433bfb8a87edc149c06076b35b434e77b0..6bbd345f453543015dcdc8f4f20fbbec137f5437 100644 (file)
@@ -21,17 +21,16 @@ import java.awt.Rectangle;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
-import java.util.Iterator;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.poi.ddf.AbstractEscherOptRecord;
 import org.apache.poi.ddf.EscherArrayProperty;
 import org.apache.poi.ddf.EscherContainerRecord;
 import org.apache.poi.ddf.EscherOptRecord;
 import org.apache.poi.ddf.EscherProperties;
-import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.ddf.EscherSimpleProperty;
-import org.apache.poi.ddf.EscherTextboxRecord;
 import org.apache.poi.hslf.record.RecordTypes;
 import org.apache.poi.sl.usermodel.ShapeContainer;
 import org.apache.poi.sl.usermodel.TableShape;
@@ -46,11 +45,6 @@ import org.apache.poi.util.Units;
 public final class HSLFTable extends HSLFGroupShape
 implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> {
 
-    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<HSLFShape,HSLFTextParagraph> {
      * @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<HSLFShape,HSLFTextParagraph> {
      * @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<HSLFShape,HSLFTextParagraph> parent) {
+    protected HSLFTable(int numRows, int numCols, ShapeContainer<HSLFShape,HSLFTextParagraph> 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<HSLFShape,HSLFTextParagraph> {
         }
         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<HSLFShape,HSLFTextParagraph> {
     }
 
     /**
-     * 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 <code>EscherSpContainer</code> container which holds information about this shape
      * @param parent       the parent of the shape
      */
-    public HSLFTable(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
+    protected HSLFTable(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent) {
         super(escherRecord, parent);
     }
 
@@ -131,9 +125,12 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
     protected void afterInsert(HSLFSheet sh){
         super.afterInsert(sh);
 
-        EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
-        List<EscherRecord> 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<HSLFLine> lineSet = new HashSet<HSLFLine>();
+        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<HSLFShape> {
+        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<HSLFTableCell> htc = new ArrayList<HSLFTableCell>();
+        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<HSLFTableCell[]> lst = new ArrayList<HSLFTableCell[]>();
+        List<HSLFTableCell> row = new ArrayList<HSLFTableCell>();
 
+        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<HSLFShape> shapeList = getShapes();
-
-        Iterator<HSLFShape> 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<HSLFShape>(){
-            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<List<HSLFShape>> lst = new ArrayList<List<HSLFShape>>();
-        List<HSLFShape> row = null;
-        for (HSLFShape sh : shapeList) {
-            if(sh instanceof HSLFTextShape){
-                Rectangle anchor = sh.getAnchor();
-                if(anchor.y != y0){
-                    y0 = anchor.y;
-                    row = new ArrayList<HSLFShape>();
-                    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<LineRect> lines = new ArrayList<LineRect>();
+        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 <code>SlideShow</code> this shape belongs to
      *
@@ -232,151 +310,102 @@ implements HSLFShapeContainer, TableShape<HSLFShape,HSLFTextParagraph> {
      */
     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);
+        }
     }
 }
index e3737e5e18332d98403cc60ded6e99af1dfbe11c..80341aa35402e666e5b7e3be6154cc822ae347e3 100644 (file)
 
 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<HSLFSh
     protected static final int DEFAULT_WIDTH = 100;
     protected static final int DEFAULT_HEIGHT = 40;
 
-    private HSLFLine borderLeft;
-    private HSLFLine borderRight;
-    private HSLFLine borderTop;
-    private HSLFLine borderBottom;
+    /* package */ HSLFLine borderLeft;
+    /* package */ HSLFLine borderRight;
+    /* package */ HSLFLine borderTop;
+    /* package */ HSLFLine borderBottom;
 
     /**
      * Create a TableCell object and initialize it from the supplied Record container.
@@ -46,7 +51,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh
      * @param escherRecord       EscherSpContainer which holds information about this shape
      * @param parent    the parent of the shape
      */
-   protected HSLFTableCell(EscherContainerRecord escherRecord, ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
+   protected HSLFTableCell(EscherContainerRecord escherRecord, HSLFTable parent){
         super(escherRecord, parent);
     }
 
@@ -56,7 +61,7 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh
      * @param parent    the parent of this Shape. For example, if this text box is a cell
      * in a table then the parent is Table.
      */
-    public HSLFTableCell(ShapeContainer<HSLFShape,HSLFTextParagraph> parent){
+    public HSLFTableCell(HSLFTable parent){
         super(parent);
 
         setShapeType(ShapeType.RECT);
@@ -76,82 +81,320 @@ public final class HSLFTableCell extends HSLFTextBox implements TableCell<HSLFSh
         return _escherContainer;
     }
 
-    protected void anchorBorder(int type, HSLFLine line){
+    private void anchorBorder(BorderEdge edge, final HSLFLine line) {
+        if (line == null) {
+            return;
+        }
         Rectangle cellAnchor = getAnchor();
         Rectangle lineAnchor = new Rectangle();
-        switch(type){
-            case HSLFTable.BORDER_TOP:
+        switch(edge){
+            case top:
                 lineAnchor.x = cellAnchor.x;
                 lineAnchor.y = cellAnchor.y;
                 lineAnchor.width = cellAnchor.width;
                 lineAnchor.height = 0;
                 break;
-            case HSLFTable.BORDER_RIGHT:
+            case right:
                 lineAnchor.x = cellAnchor.x + cellAnchor.width;
                 lineAnchor.y = cellAnchor.y;
                 lineAnchor.width = 0;
                 lineAnchor.height = cellAnchor.height;
                 break;
-            case HSLFTable.BORDER_BOTTOM:
+            case bottom:
                 lineAnchor.x = cellAnchor.x;
                 lineAnchor.y = cellAnchor.y + cellAnchor.height;
                 lineAnchor.width = cellAnchor.width;
                 lineAnchor.height = 0;
                 break;
-            case HSLFTable.BORDER_LEFT:
+            case left:
                 lineAnchor.x = cellAnchor.x;
                 lineAnchor.y = cellAnchor.y;
                 lineAnchor.width = 0;
                 lineAnchor.height = cellAnchor.height;
                 break;
             default:
-                throw new IllegalArgumentException("Unknown border type: " + type);
+                throw new IllegalArgumentException();
         }
         line.setAnchor(lineAnchor);
     }
 
-    public HSLFLine getBorderLeft() {
-        return borderLeft;
+    public void setAnchor(Rectangle anchor){
+        super.setAnchor(anchor);
+
+        anchorBorder(BorderEdge.top, borderTop);
+        anchorBorder(BorderEdge.right, borderRight);
+        anchorBorder(BorderEdge.bottom, borderBottom);
+        anchorBorder(BorderEdge.left, borderLeft);
     }
 
-    public void setBorderLeft(HSLFLine line) {
-        if(line != null) anchorBorder(HSLFTable.BORDER_LEFT, line);
-        this.borderLeft = line;
+    @Override
+    public StrokeStyle getBorderStyle(final BorderEdge edge) {
+        final Double width = getBorderWidth(edge); 
+        return (width == null) ? null : new StrokeStyle() {
+            public PaintStyle getPaint() {
+                return DrawPaint.createSolidPaint(getBorderColor(edge));
+            }
+
+            public LineCap getLineCap() {
+                return null;
+            }
+
+            public LineDash getLineDash() {
+                return getBorderDash(edge);
+            }
+
+            public LineCompound getLineCompound() {
+                return getBorderCompound(edge);
+            }
+
+            public double getLineWidth() {
+                return width;
+            }
+        };
     }
 
-    public HSLFLine getBorderRight() {
-        return borderRight;
+    @Override
+    public void setBorderStyle(BorderEdge edge, StrokeStyle style) {
+        if (style == null) {
+            throw new IllegalArgumentException("StrokeStyle needs to be specified.");
+        }
+        
+        // setting the line cap is not implemented, as the border lines aren't connected
+        
+        LineCompound compound = style.getLineCompound();
+        if (compound != null) {
+            setBorderCompound(edge, compound);
+        }
+        
+        LineDash dash = style.getLineDash();
+        if (dash != null) {
+            setBorderDash(edge, dash);
+        }
+        
+        double width = style.getLineWidth();
+        setBorderWidth(edge, width);
     }
 
-    public void setBorderRight(HSLFLine line) {
-        if(line != null) anchorBorder(HSLFTable.BORDER_RIGHT, line);
-        this.borderRight = line;
+    
+    public Double getBorderWidth(BorderEdge edge) {
+        HSLFLine l;
+        switch (edge) {
+            case bottom: l = borderBottom; break;
+            case top: l = borderTop; break;
+            case right: l = borderRight; break;
+            case left: l = borderLeft; break;
+            default: throw new IllegalArgumentException();
+        }
+        return (l == null) ? null : l.getLineWidth();
+    }
+    
+    @Override
+    public void setBorderWidth(BorderEdge edge, double width) {
+        HSLFLine l = addLine(edge);
+        l.setLineWidth(width);
     }
 
-    public HSLFLine getBorderTop() {
-        return borderTop;
+    public Color getBorderColor(BorderEdge edge) {
+        HSLFLine l;
+        switch (edge) {
+            case bottom: l = borderBottom; break;
+            case top: l = borderTop; break;
+            case right: l = borderRight; break;
+            case left: l = borderLeft; break;
+            default: throw new IllegalArgumentException();
+        }
+        return (l == null) ? null : l.getLineColor();
     }
 
-    public void setBorderTop(HSLFLine line) {
-        if(line != null) anchorBorder(HSLFTable.BORDER_TOP, line);
-        this.borderTop = line;
+    @Override
+    public void setBorderColor(BorderEdge edge, Color color) {
+        if (edge == null || color == null) {
+            throw new IllegalArgumentException("BorderEdge and/or Color need to be specified.");
+        }
+        
+        HSLFLine l = addLine(edge);
+        l.setLineColor(color);
     }
 
-    public HSLFLine getBorderBottom() {
-        return borderBottom;
+    public LineDash getBorderDash(BorderEdge edge) {
+        HSLFLine l;
+        switch (edge) {
+            case bottom: l = borderBottom; break;
+            case top: l = borderTop; break;
+            case right: l = borderRight; break;
+            case left: l = borderLeft; break;
+            default: throw new IllegalArgumentException();
+        }
+        return (l == null) ? null : l.getLineDash();        
+    }
+    
+    @Override
+    public void setBorderDash(BorderEdge edge, LineDash dash) {
+        if (edge == null || dash == null) {
+            throw new IllegalArgumentException("BorderEdge and/or LineDash need to be specified.");
+        }
+        
+        HSLFLine l = addLine(edge);
+        l.setLineDash(dash);
     }
 
-    public void setBorderBottom(HSLFLine line) {
-        if(line != null) anchorBorder(HSLFTable.BORDER_BOTTOM, line);
-        this.borderBottom = line;
+    public LineCompound getBorderCompound(BorderEdge edge) {
+        HSLFLine l;
+        switch (edge) {
+            case bottom: l = borderBottom; break;
+            case top: l = borderTop; break;
+            case right: l = borderRight; break;
+            case left: l = borderLeft; break;
+            default: throw new IllegalArgumentException();
+        }
+        return (l == null) ? null : l.getLineCompound();        
+    }
+    
+    @Override
+    public void setBorderCompound(BorderEdge edge, LineCompound compound) {
+        if (edge == null || compound == null) {
+            throw new IllegalArgumentException("BorderEdge and/or LineCompound need to be specified.");
+        }
+        
+        HSLFLine l = addLine(edge);
+        l.setLineCompound(compound);
     }
 
-    public void setAnchor(Rectangle anchor){
-        super.setAnchor(anchor);
 
-        if(borderTop != null) anchorBorder(HSLFTable.BORDER_TOP, borderTop);
-        if(borderRight != null) anchorBorder(HSLFTable.BORDER_RIGHT, borderRight);
-        if(borderBottom != null) anchorBorder(HSLFTable.BORDER_BOTTOM, borderBottom);
-        if(borderLeft != null) anchorBorder(HSLFTable.BORDER_LEFT, borderLeft);
+    protected HSLFLine addLine(BorderEdge edge) {
+        switch (edge) {
+            case bottom: {
+                if (borderBottom == null) {
+                    borderBottom = createBorder(edge);
+                    HSLFTableCell c = getSiblingCell(1,0);
+                    if (c != null) {
+                        assert(c.borderTop == null);
+                        c.borderTop = borderBottom;
+                    }
+                }
+                return borderBottom;
+            }
+            case top: {
+                if (borderTop == null) {
+                    borderTop = createBorder(edge);
+                    HSLFTableCell c = getSiblingCell(-1,0);
+                    if (c != null) {
+                        assert(c.borderBottom == null);
+                        c.borderBottom = borderTop;
+                    }
+                }
+                return borderTop;
+            }
+            case right: {
+                if (borderRight == null) {
+                    borderRight = createBorder(edge);
+                    HSLFTableCell c = getSiblingCell(0,1);
+                    if (c != null) {
+                        assert(c.borderLeft == null);
+                        c.borderLeft = borderRight;
+                    }
+                }
+                return borderRight;
+            }
+            case left: {
+                if (borderLeft == null) {
+                    borderLeft = createBorder(edge);
+                    HSLFTableCell c = getSiblingCell(0,-1);
+                    if (c != null) {
+                        assert(c.borderRight == null);
+                        c.borderRight = borderLeft;
+                    }
+                }
+                return borderLeft;
+            }
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    @Override
+    public void removeBorder(BorderEdge edge) {
+        switch (edge) {
+            case bottom: {
+                if (borderBottom == null) break;
+                getParent().removeShape(borderBottom);
+                borderBottom = null;
+                HSLFTableCell c = getSiblingCell(1,0);
+                if (c != null) {
+                    c.borderTop = null;
+                }
+                break;
+            }
+            case top: {
+                if (borderTop == null) break;
+                getParent().removeShape(borderTop);
+                borderTop = null;
+                HSLFTableCell c = getSiblingCell(-1,0);
+                if (c != null) {
+                    c.borderBottom = null;
+                }
+                break;
+            }
+            case right: {
+                if (borderRight == null) break;
+                getParent().removeShape(borderRight);
+                borderRight = null;
+                HSLFTableCell c = getSiblingCell(0,1);
+                if (c != null) {
+                    c.borderLeft = null;
+                }
+                break;
+            }
+            case left: {
+                if (borderLeft == null) break;
+                getParent().removeShape(borderLeft);
+                borderLeft = null;
+                HSLFTableCell c = getSiblingCell(0,-1);
+                if (c != null) {
+                    c.borderRight = null;
+                }
+                break;
+            }
+            default:
+                throw new IllegalArgumentException();
+        }
+    }
+
+    protected HSLFTableCell getSiblingCell(int row, int col) {
+        return getParent().getRelativeCell(this, row, col);
+    }
+
+    /**
+     * Create a border to format this table
+     *
+     * @return the created border
+     */
+    private HSLFLine createBorder(BorderEdge edge) {
+        HSLFTable table = getParent();
+        HSLFLine line = new HSLFLine(table);
+        table.addShape(line);
+
+        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);
+
+        anchorBorder(edge, line);
+        
+        return line;
+    }
+
+    protected void applyLineProperties(BorderEdge edge, HSLFLine other) {
+        HSLFLine line = addLine(edge);
+        line.setLineWidth(other.getLineWidth());
+        line.setLineColor(other.getLineColor());
+        // line.setLineCompound(other.getLineCompound());
+        // line.setLineDashing(other.getLineDashing());
+    }
+
+    @Override
+    public HSLFTable getParent() {
+        return (HSLFTable)super.getParent();
     }
 }
index 39fe74c2a9b66ff8f4fbab99f1549452c48dce7c..76969a4713af4de62122c2776bded7367c7f350a 100644 (file)
@@ -69,7 +69,7 @@ import org.apache.poi.util.Units;
  * This class represents a run of text in a powerpoint document. That\r
  *  run could be text on a sheet, or text in a note.\r
  *  It is only a very basic class for now\r
- * \r
+ *\r
  * @author Nick Burch\r
  */\r
 \r
@@ -98,18 +98,18 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     private int shapeId;\r
 \r
     private StyleTextProp9Atom styleTextProp9Atom;\r
-    \r
+\r
     private boolean _dirty = false;\r
 \r
     /**\r
     * Constructs a Text Run from a Unicode text block.\r
     * Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.\r
-     * \r
+     *\r
     * @param tha the TextHeaderAtom that defines what's what\r
     * @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided\r
     * @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided\r
      */\r
-       /* package */ HSLFTextParagraph(\r
+    /* package */ HSLFTextParagraph(\r
         TextHeaderAtom tha,\r
         TextBytesAtom tba,\r
         TextCharsAtom tca\r
@@ -137,10 +137,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         _runs.add(run);\r
     }\r
 \r
-    /**\r
-        * Fetch the rich text runs (runs of text with the same styling) that\r
-        *  are contained within this block of text\r
-     */\r
+    @Override\r
     public List<HSLFTextRun> getTextRuns() {\r
         return _runs;\r
     }\r
@@ -193,7 +190,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
 \r
     /**\r
      * Sets the index of the paragraph in the SLWT container\r
-     * \r
+     *\r
      * @param index\r
      */\r
     protected void setIndex(int index) {\r
@@ -241,7 +238,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     /**\r
      * Returns records that make up the list of text paragraphs\r
      * (there can be misc InteractiveInfo, TxInteractiveInfo and other records)\r
-     * \r
+     *\r
      * @return text run records\r
      */\r
     public Record[] getRecords() {\r
@@ -278,7 +275,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     }\r
 \r
     /** Numbered List info */\r
-       public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {\r
+    public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {\r
         this.styleTextProp9Atom = styleTextProp9Atom;\r
     }\r
 \r
@@ -286,7 +283,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     public StyleTextProp9Atom getStyleTextProp9Atom() {\r
         return this.styleTextProp9Atom;\r
     }\r
-    \r
+\r
     @Override\r
     public Iterator<HSLFTextRun> iterator() {\r
         return _runs.iterator();\r
@@ -342,13 +339,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         if (!_runs.isEmpty()) {\r
             d = _runs.get(0).getFontSize();\r
         }\r
-        \r
+\r
         return (d != null) ? d : 12d;\r
     }\r
 \r
     /**\r
      * Sets the type of horizontal alignment for the paragraph.\r
-     * \r
+     *\r
      * @param align - the type of alignment\r
      */\r
     public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) {\r
@@ -386,7 +383,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     public FontAlign getFontAlign() {\r
         TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME, this);\r
         if (tp == null) return null;\r
-        \r
+\r
         switch (tp.getValue()) {\r
             case FontAlignmentProp.BASELINE: return FontAlign.BASELINE;\r
             case FontAlignmentProp.TOP: return FontAlign.TOP;\r
@@ -413,8 +410,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         assert(startAt != null);\r
         return startAt.intValue();\r
     }\r
-    \r
-    \r
+\r
+\r
     @Override\r
     public BulletStyle getBulletStyle() {\r
         if (!isBullet() && getAutoNumberingScheme() == null) return null;\r
@@ -440,7 +437,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
             public void setBulletFontColor(Color color) {\r
                 setBulletFontColor(DrawPaint.createSolidPaint(color));\r
             }\r
-            \r
+\r
             @Override\r
             public void setBulletFontColor(PaintStyle color) {\r
                 if (!(color instanceof SolidPaint)) {\r
@@ -450,7 +447,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
                 Color col = DrawPaint.applyColorTransform(sp.getSolidColor());\r
                 HSLFTextParagraph.this.setBulletColor(col);\r
             }\r
-            \r
+\r
             @Override\r
             public PaintStyle getBulletFontColor() {\r
                 Color col = HSLFTextParagraph.this.getBulletColor();\r
@@ -617,7 +614,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         // TODO: implement\r
         return null;\r
     }\r
-    \r
+\r
     private Double getPctOrPoints(String propName) {\r
         TextProp tp = getPropVal(_paragraphStyle, propName, this);\r
         if (tp == null) return null;\r
@@ -632,7 +629,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         }\r
         setParagraphTextPropVal(propName, ival);\r
     }\r
-    \r
+\r
     private boolean getFlag(int index) {\r
         BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME, this);\r
         return (tp == null) ? false : tp.getSubValue(index);\r
@@ -672,7 +669,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     /**\r
      * Returns the named TextProp, either by fetching it (if it exists) or\r
      * adding it (if it didn't)\r
-     * \r
+     *\r
      * @param props the TextPropCollection to fetch from / add into\r
      * @param name the name of the TextProp to fetch/add\r
      * @param val the value, null if unset\r
@@ -682,15 +679,15 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
             props.removeByName(name);\r
             return;\r
         }\r
-        \r
+\r
         // Fetch / Add the TextProp\r
         TextProp tp = props.addWithName(name);\r
         tp.setValue(val);\r
     }\r
-    \r
+\r
     /**\r
      * Check and add linebreaks to text runs leading other paragraphs\r
-     * \r
+     *\r
      * @param paragraphs\r
      */\r
     protected static void fixLineEndings(List<HSLFTextParagraph> paragraphs) {\r
@@ -710,7 +707,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
 \r
     /**\r
      * Search for a StyleTextPropAtom is for this text header (list of paragraphs)\r
-     * \r
+     *\r
      * @param header the header\r
      * @param textLen the length of the rawtext, or -1 if the length is not known\r
      */\r
@@ -868,7 +865,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
                 throw new RuntimeException("failed dummy write", e);\r
             }\r
         }\r
-        \r
+\r
         for (HSLFTextParagraph p : paragraphs) {\r
             p._dirty = false;\r
         }\r
@@ -877,7 +874,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     /**\r
      * Adds the supplied text onto the end of the TextParagraphs,\r
      * creating a new RichTextRun for it to sit in.\r
-     * \r
+     *\r
      * @param text the text string used by this object.\r
      */\r
     protected static HSLFTextRun appendText(List<HSLFTextParagraph> paragraphs, String text, boolean newParagraph) {\r
@@ -889,9 +886,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         HSLFTextParagraph htp = paragraphs.get(paragraphs.size() - 1);\r
         HSLFTextRun htr = htp.getTextRuns().get(htp.getTextRuns().size() - 1);\r
 \r
-        boolean isFirst = !newParagraph;\r
+        boolean addParagraph = newParagraph;\r
         for (String rawText : text.split("(?<=\r)")) {\r
-            if (!isFirst) {\r
+            // special case, if last text paragraph or run is empty, we will reuse it\r
+            boolean lastRunEmpty = (htr.getLength() == 0);\r
+            boolean lastParaEmpty = lastRunEmpty && (htp.getTextRuns().size() == 1);\r
+\r
+            if (addParagraph && !lastParaEmpty) {\r
                 TextPropCollection tpc = htp.getParagraphStyle();\r
                 HSLFTextParagraph prevHtp = htp;\r
                 htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);\r
@@ -901,11 +902,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
                 htp.supplySheet(prevHtp.getSheet());\r
                 paragraphs.add(htp);\r
             }\r
-            isFirst = false;\r
+            addParagraph = true;\r
 \r
-            TextPropCollection tpc = htr.getCharacterStyle();\r
-            // special case, last text run is empty, we will reuse it\r
-            if (htr.getLength() > 0) {\r
+            if (!lastRunEmpty) {\r
+                TextPropCollection tpc = htr.getCharacterStyle();\r
                 htr = new HSLFTextRun(htp);\r
                 htr.getCharacterStyle().copy(tpc);\r
                 htp.addTextRun(htr);\r
@@ -921,7 +921,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     /**\r
      * Sets (overwrites) the current text.\r
      * Uses the properties of the first paragraph / textrun\r
-     * \r
+     *\r
      * @param text the text string used by this object.\r
      */\r
     public static HSLFTextRun setText(List<HSLFTextParagraph> paragraphs, String text) {\r
@@ -980,7 +980,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     /**\r
      * Converts raw text from the text paragraphs to a formatted string,\r
      * i.e. it converts certain control characters used in the raw txt\r
-     * \r
+     *\r
      * @param rawText the raw text\r
      * @param runType the run type of the shape, paragraph or headerAtom.\r
      *        use -1 if unknown\r
@@ -1024,7 +1024,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
      * Scans through the supplied record array, looking for\r
      * a TextHeaderAtom followed by one of a TextBytesAtom or\r
      * a TextCharsAtom. Builds up TextRuns from these\r
-     * \r
+     *\r
      * @param wrapper an EscherTextboxWrapper\r
      */\r
     protected static List<HSLFTextParagraph> findTextParagraphs(EscherTextboxWrapper wrapper, HSLFSheet sheet) {\r
@@ -1103,7 +1103,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
      * Scans through the supplied record array, looking for\r
      * a TextHeaderAtom followed by one of a TextBytesAtom or\r
      * a TextCharsAtom. Builds up TextRuns from these\r
-     * \r
+     *\r
      * @param records the records to build from\r
      */\r
     protected static List<List<HSLFTextParagraph>> findTextParagraphs(Record[] records) {\r
@@ -1272,7 +1272,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         EscherTextboxWrapper wrapper = new EscherTextboxWrapper();\r
         return createEmptyParagraph(wrapper);\r
     }\r
-    \r
+\r
     protected static List<HSLFTextParagraph> createEmptyParagraph(EscherTextboxWrapper wrapper) {\r
         TextHeaderAtom tha = new TextHeaderAtom();\r
         tha.setParentRecord(wrapper);\r
@@ -1301,10 +1301,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
     public EscherTextboxWrapper getTextboxWrapper() {\r
         return (EscherTextboxWrapper) _headerAtom.getParentRecord();\r
     }\r
-    \r
+\r
     protected static Color getColorFromColorIndexStruct(int rgb, HSLFSheet sheet) {\r
         int cidx = rgb >>> 24;\r
-        Color tmp; \r
+        Color tmp;\r
         switch (cidx) {\r
             // Background ... Accent 3 color\r
             case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:\r
@@ -1333,15 +1333,15 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
         setPropVal(_paragraphStyle, propName, val);\r
         setDirty();\r
     }\r
-    \r
+\r
     /**\r
      * marks this paragraph dirty, so its records will be renewed on save\r
      */\r
     public void setDirty() {\r
         _dirty = true;\r
     }\r
-    \r
+\r
     public boolean isDirty() {\r
         return _dirty;\r
     }\r
-}\r
+}
\ No newline at end of file
index fbb908c1c70136cb52758bb50fe8a5e8f1e88d18..a636d346c3d89a18f4b899414c98b6587e7da4e4 100644 (file)
@@ -157,44 +157,32 @@ public final class HSLFTextRun implements TextRun {
 
        // --------------- Friendly getters / setters on rich text properties -------
 
-       /**
-        * Is the text bold?
-        */
+       @Override
        public boolean isBold() {
                return isCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX);
        }
 
-       /**
-        * Is the text bold?
-        */
+       @Override
        public void setBold(boolean bold) {
                setCharFlagsTextPropVal(CharFlagsTextProp.BOLD_IDX, bold);
        }
 
-       /**
-        * Is the text italic?
-        */
+       @Override
        public boolean isItalic() {
                return isCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX);
        }
 
-       /**
-        * Is the text italic?
-        */
+       @Override
        public void setItalic(boolean italic) {
                setCharFlagsTextPropVal(CharFlagsTextProp.ITALIC_IDX, italic);
        }
 
-       /**
-        * Is the text underlined?
-        */
+       @Override
        public boolean isUnderlined() {
                return isCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX);
        }
 
-       /**
-        * Is the text underlined?
-        */
+       @Override
        public void setUnderlined(boolean underlined) {
                setCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX, underlined);
        }
@@ -227,16 +215,12 @@ public final class HSLFTextRun implements TextRun {
                setCharFlagsTextPropVal(CharFlagsTextProp.RELIEF_IDX, flag);
        }
 
-       /**
-        * Gets the strikethrough flag
-        */
+       @Override
        public boolean isStrikethrough() {
                return isCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX);
        }
 
-       /**
-        * Sets the strikethrough flag
-        */
+       @Override
        public void setStrikethrough(boolean flag) {
                setCharFlagsTextPropVal(CharFlagsTextProp.STRIKETHROUGH_IDX, flag);
        }
@@ -288,10 +272,7 @@ public final class HSLFTextRun implements TextRun {
                setCharTextPropVal("font.index", idx);
        }
 
-
-       /**
-        * Sets the font name to use
-        */
+       @Override
        public void setFontFamily(String fontFamily) {
            HSLFSheet sheet = parentParagraph.getSheet();
            HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow();
@@ -301,13 +282,10 @@ public final class HSLFTextRun implements TextRun {
                        return;
                }
                // Get the index for this font (adding if needed)
-               int fontIdx = slideShow.getFontCollection().addFont(fontFamily);
+               Integer fontIdx = (fontFamily == null) ? null : slideShow.getFontCollection().addFont(fontFamily);
                setCharTextPropVal("font.index", fontIdx);
        }
 
-       /**
-        * Gets the font name
-        */
        @Override
        public String getFontFamily() {
         HSLFSheet sheet = parentParagraph.getSheet();
@@ -373,12 +351,14 @@ public final class HSLFTextRun implements TextRun {
         return TextCap.NONE;
     }
 
+    @Override
     public boolean isSubscript() {
-        return false;
+        return getSuperscript() < 0;
     }
 
+    @Override
     public boolean isSuperscript() {
-        return false;
+        return getSuperscript() > 0;
     }
 
     public byte getPitchAndFamily() {
index 1b5bbb83fd08d279ec23b68066d22d3aaa974799..f24173e20428bb13be9d7fb0d7deacbbcec45222 100644 (file)
 
 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<HSLFShape,HSLFTextParagraph> {
     /* 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<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
             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<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
         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 <code>Wrap*</code> 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<HSLFShape,HSLFTextParagraph> {
         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<HSLFShape,HSLFTextParagraph> {
           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<HSLFTextParagraph> paras = getTextParagraphs();
@@ -783,5 +821,64 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
         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
index b26e10215f420c45c1ea37627e4c32c48bda1320..c601ca04b718bd8c0492c6e2f364f20fbb310325 100644 (file)
@@ -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);
index f7fe4c43f4ec76336ad1bc9dc5fe4e9828c88088..3ce7a71b9987e86ee291f0c09192d26eb8de00d1 100644 (file)
@@ -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);
index 8032d2da3e483c96a00c43a3157f5c0ae9095bf2..9b11555b1ac5d594ef7c8ba0e4a320ab0dc05949 100644 (file)
@@ -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<HSLFShape> 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){
 
index 2270cd420f590c76b74d51bb0fc7103c88fe04db..d32114a7f8efc05c7b81b85f4aea6aaf86f4115a 100644 (file)
 
 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<rows; row++) {
+            for (int col=0; col<cols; col++) {
+                HSLFTableCell c = table.getCell(row, col);
+                c.setText("r"+row+"c"+col);
+            }
+        }
+        
+        new DrawTableShape(table).setAllBorders(1.0, Color.black, StrokeStyle.LineDash.DASH_DOT);
+        
+        table.setAnchor(new Rectangle(100, 100, 400, 400));
+        
+        Rectangle rectExp = new Rectangle(420,367,80,133);
+        Rectangle rectAct = table.getCell(rows-1, cols-1).getAnchor();
+        assertEquals(rectExp, rectAct);
+    }
+    
     @Test
     public void testTable() throws Exception {
                HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("54111.ppt"));
index 1cbf238de690e367b47c70b98cf3731319a236b6..f7db8f5a80d18368f83de95906b1437c8b100e4f 100644 (file)
@@ -571,4 +571,13 @@ public final class TestTextRun {
         }
     }
 
+       @Test
+       public void testAppendEmpty() throws IOException {
+        HSLFSlideShow ppt = new HSLFSlideShow();
+        HSLFSlide s = ppt.createSlide();
+        HSLFTextBox title = s.addTitle();
+        title.setText("");
+        title.appendText("\n", true);
+        title.appendText("para", true);
+       }
 }