From: Andreas Beeker Date: Mon, 27 Apr 2015 20:13:43 +0000 (+0000) Subject: committing intermediate results - hslf is mostly migrated to common interface - junit... X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=e6413c3fe72a3b9b8f68c2378f2c885d10217a41;p=poi.git committing intermediate results - hslf is mostly migrated to common interface - junit tests partly fail - still a few compile errors - xslf drawing works - hslf drawing is not yet tested git-svn-id: https://svn.apache.org/repos/asf/poi/branches/common_sl@1676365 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java index 7a4b20c187..229d7576e7 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java +++ b/src/examples/src/org/apache/poi/hslf/examples/ApacheconEU08.java @@ -60,22 +60,22 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); tr1.setText("POI-HSLF"); box1.setAnchor(new Rectangle(54, 78, 612, 115)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); tr2.setText("Java API To Access Microsoft PowerPoint Format Files"); box2.setAnchor(new Rectangle(108, 204, 504, 138)); slide.addShape(box2); HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextParagraph tr3 = box3.getTextParagraph(); - tr3.getRichTextRuns()[0].setFontSize(32); + HSLFTextParagraph tr3 = box3.getTextParagraphs(); + tr3.getTextRuns()[0].setFontSize(32); box3.setHorizontalAlignment(HSLFTextBox.AlignCenter); tr3.setText( "Yegor Kozlov\r" + @@ -88,14 +88,14 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("What is HSLF?"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.BODY_TYPE); tr2.setText("HorribleSLideshowFormat is the POI Project's pure Java implementation " + "of the Powerpoint binary file format. \r" + @@ -111,25 +111,25 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("HSLF in a Nutshell"); box1.setAnchor(new Rectangle(36, 15, 648, 65)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.BODY_TYPE); tr2.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" + "Comprehensive support of PowerPoint objects"); - tr2.getRichTextRuns()[0].setFontSize(28); + tr2.getTextRuns()[0].setFontSize(28); box2.setAnchor(new Rectangle(36, 80, 648, 200)); slide.addShape(box2); HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextParagraph tr3 = box3.getTextParagraph(); + HSLFTextParagraph tr3 = box3.getTextParagraphs(); tr3.setRunType(TextHeaderAtom.BODY_TYPE); tr3.setText( "Rich text\r" + @@ -137,13 +137,13 @@ public final class ApacheconEU08 { "Shapes\r" + "Pictures\r" + "Master slides"); - tr3.getRichTextRuns()[0].setFontSize(24); - tr3.getRichTextRuns()[0].setIndentLevel(1); + tr3.getTextRuns()[0].setFontSize(24); + tr3.getTextRuns()[0].setIndentLevel(1); box3.setAnchor(new Rectangle(36, 265, 648, 150)); slide.addShape(box3); HSLFTextBox box4 = new HSLFTextBox(); - HSLFTextParagraph tr4 = box4.getTextParagraph(); + HSLFTextParagraph tr4 = box4.getTextParagraphs(); tr4.setRunType(TextHeaderAtom.BODY_TYPE); tr4.setText("Access to low level data structures"); box4.setAnchor(new Rectangle(36, 430, 648, 50)); @@ -162,8 +162,8 @@ public final class ApacheconEU08 { for (int j = 0; j < txt1[i].length; j++) { TableCell cell = table1.getCell(i, j); cell.setText(txt1[i][j]); - cell.getTextParagraph().getRichTextRuns()[0].setFontSize(10); - HSLFTextRun rt = cell.getTextParagraph().getRichTextRuns()[0]; + cell.getTextParagraphs().getTextRuns()[0].setFontSize(10); + HSLFTextRun rt = cell.getTextParagraphs().getTextRuns()[0]; rt.setFontName("Arial"); rt.setBold(true); if(i == 0){ @@ -197,10 +197,10 @@ public final class ApacheconEU08 { HSLFTextBox box1 = new HSLFTextBox(); box1.setHorizontalAlignment(HSLFTextBox.AlignCenter); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setText("The source code is available at\r" + "http://people.apache.org/~yegor/apachecon_eu08/"); - HSLFTextRun rt = tr1.getRichTextRuns()[0]; + HSLFTextRun rt = tr1.getTextRuns()[0]; rt.setFontSize(24); box1.setAnchor(new Rectangle(80, 356, 553, 65)); slide.addShape(box1); @@ -211,14 +211,14 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("HSLF in Action - 1\rData Extraction"); box1.setAnchor(new Rectangle(36, 21, 648, 100)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.BODY_TYPE); tr2.setText( "Text from slides and notes\r" + @@ -234,22 +234,22 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("HSLF in Action - 2"); box1.setAnchor(new Rectangle(36, 20, 648, 90)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); - tr2.getRichTextRuns()[0].setFontSize(18); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); + tr2.getTextRuns()[0].setFontSize(18); tr2.setText("Creating a simple presentation from scratch"); box2.setAnchor(new Rectangle(170, 100, 364, 30)); slide.addShape(box2); HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextParagraph tr3 = box3.getTextParagraph(); - HSLFTextRun rt3 = tr3.getRichTextRuns()[0]; + HSLFTextParagraph tr3 = box3.getTextParagraphs(); + HSLFTextRun rt3 = tr3.getTextRuns()[0]; rt3.setFontName("Courier New"); rt3.setFontSize(8); tr3.setText( @@ -296,7 +296,7 @@ public final class ApacheconEU08 { HSLFTextBox box2 = new HSLFTextBox(); box2.setHorizontalAlignment(HSLFTextBox.AlignCenter); box2.setVerticalAlignment(HSLFTextBox.AnchorMiddle); - box2.getTextParagraph().setText("Java Code"); + box2.getTextParagraphs().setText("Java Code"); box2.getFill().setForegroundColor(new Color(187, 224, 227)); box2.setLineColor(Color.black); box2.setLineWidth(0.75); @@ -306,7 +306,7 @@ public final class ApacheconEU08 { HSLFTextBox box3 = new HSLFTextBox(); box3.setHorizontalAlignment(HSLFTextBox.AlignCenter); box3.setVerticalAlignment(HSLFTextBox.AnchorMiddle); - box3.getTextParagraph().setText("*.ppt file"); + box3.getTextParagraphs().setText("*.ppt file"); box3.setLineWidth(0.75); box3.setLineColor(Color.black); box3.getFill().setForegroundColor(new Color(187, 224, 227)); @@ -325,14 +325,14 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("Wait, there is more!"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.BODY_TYPE); tr2.setText( "Rich text\r" + @@ -347,22 +347,22 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("HSLF in Action - 3"); box1.setAnchor(new Rectangle(36, 20, 648, 50)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); - tr2.getRichTextRuns()[0].setFontSize(18); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); + tr2.getTextRuns()[0].setFontSize(18); tr2.setText("PPGraphics2D: PowerPoint Graphics2D driver"); box2.setAnchor(new Rectangle(178, 70, 387, 30)); slide.addShape(box2); HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextParagraph tr3 = box3.getTextParagraph(); - HSLFTextRun rt3 = tr3.getRichTextRuns()[0]; + HSLFTextParagraph tr3 = box3.getTextParagraphs(); + HSLFTextRun rt3 = tr3.getTextRuns()[0]; rt3.setFontName("Courier New"); rt3.setFontSize(8); tr3.setText( @@ -449,16 +449,16 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.TITLE_TYPE); tr1.setText("HSLF Development Plans"); box1.setAnchor(new Rectangle(36, 21, 648, 90)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.BODY_TYPE); - tr2.getRichTextRuns()[0].setFontSize(32); + tr2.getTextRuns()[0].setFontSize(32); tr2.setText( "Support for more PowerPoint functionality\r" + "Rendering slides into java.awt.Graphics2D"); @@ -466,27 +466,27 @@ public final class ApacheconEU08 { slide.addShape(box2); HSLFTextBox box3 = new HSLFTextBox(); - HSLFTextParagraph tr3 = box3.getTextParagraph(); + HSLFTextParagraph tr3 = box3.getTextParagraphs(); tr3.setRunType(TextHeaderAtom.BODY_TYPE); - tr3.getRichTextRuns()[0].setIndentLevel(1); + tr3.getTextRuns()[0].setIndentLevel(1); tr3.setText( "A way to export slides into images or other formats"); box3.setAnchor(new Rectangle(36, 220, 648, 70)); slide.addShape(box3); HSLFTextBox box4 = new HSLFTextBox(); - HSLFTextParagraph tr4 = box4.getTextParagraph(); + HSLFTextParagraph tr4 = box4.getTextParagraphs(); tr4.setRunType(TextHeaderAtom.BODY_TYPE); - tr4.getRichTextRuns()[0].setFontSize(32); + tr4.getTextRuns()[0].setFontSize(32); tr4.setText( "Integration with Apache FOP - Formatting Objects Processor"); box4.setAnchor(new Rectangle(36, 290, 648, 90)); slide.addShape(box4); HSLFTextBox box5 = new HSLFTextBox(); - HSLFTextParagraph tr5 = box5.getTextParagraph(); + HSLFTextParagraph tr5 = box5.getTextParagraphs(); tr5.setRunType(TextHeaderAtom.BODY_TYPE); - tr5.getRichTextRuns()[0].setIndentLevel(1); + tr5.getTextRuns()[0].setIndentLevel(1); tr5.setText( "Transformation of XSL-FO into PPT\r" + "PPT2PDF transcoder"); @@ -498,14 +498,14 @@ public final class ApacheconEU08 { HSLFSlide slide = ppt.createSlide(); HSLFTextBox box1 = new HSLFTextBox(); - HSLFTextParagraph tr1 = box1.getTextParagraph(); + HSLFTextParagraph tr1 = box1.getTextParagraphs(); tr1.setRunType(TextHeaderAtom.CENTER_TITLE_TYPE); tr1.setText("Questions?"); box1.setAnchor(new Rectangle(54, 167, 612, 115)); slide.addShape(box1); HSLFTextBox box2 = new HSLFTextBox(); - HSLFTextParagraph tr2 = box2.getTextParagraph(); + HSLFTextParagraph tr2 = box2.getTextParagraphs(); tr2.setRunType(TextHeaderAtom.CENTRE_BODY_TYPE); tr2.setText( "http://poi.apache.org/hslf/\r" + diff --git a/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java b/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java index ed6dd1231d..58aaf1fff2 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java @@ -17,10 +17,7 @@ package org.apache.poi.hslf.examples; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.model.HSLFSlide; -import org.apache.poi.hslf.model.HSLFTextBox; +import org.apache.poi.hslf.usermodel.*; import java.io.FileOutputStream; @@ -39,7 +36,7 @@ public final class BulletsDemo { HSLFSlide slide = ppt.createSlide(); HSLFTextBox shape = new HSLFTextBox(); - HSLFTextRun rt = shape.getTextParagraph().getRichTextRuns()[0]; + HSLFTextRun rt = shape.getTextParagraphs().getTextRuns()[0]; shape.setText( "January\r" + "February\r" + diff --git a/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java b/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java index 99c5d7d31f..8732152324 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java +++ b/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.examples; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.model.*; import java.io.FileOutputStream; @@ -43,7 +43,7 @@ public final class CreateHyperlink { textBox1.setAnchor(new Rectangle(100, 100, 200, 50)); String text = textBox1.getText(); - Hyperlink link = new Hyperlink(); + HSLFHyperlink link = new HSLFHyperlink(); link.setAddress("http://www.apache.org"); link.setTitle(textBox1.getText()); int linkId = ppt.addHyperlink(link); @@ -58,7 +58,7 @@ public final class CreateHyperlink { textBox2.setText("Go to slide #3"); textBox2.setAnchor(new Rectangle(100, 300, 200, 50)); - Hyperlink link2 = new Hyperlink(); + HSLFHyperlink link2 = new HSLFHyperlink(); link2.setAddress(slideC); ppt.addHyperlink(link2); diff --git a/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java b/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java index 4e678ba64d..19fe496769 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/Graphics2DDemo.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.examples; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.model.*; import java.awt.*; diff --git a/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java b/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java index 068d675347..b335e1f1e1 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/HeadersFootersDemo.java @@ -16,9 +16,9 @@ ==================================================================== */ package org.apache.poi.hslf.examples; +import org.apache.poi.hslf.usermodel.HSLFSlide; import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.hslf.model.HeadersFooters; -import org.apache.poi.hslf.model.HSLFSlide; import java.io.FileOutputStream; diff --git a/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java b/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java index 89dcb636af..b9af6d2d56 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java +++ b/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java @@ -17,11 +17,7 @@ package org.apache.poi.hslf.examples; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.model.HSLFSlide; -import org.apache.poi.hslf.model.HSLFTextParagraph; -import org.apache.poi.hslf.model.Hyperlink; -import org.apache.poi.hslf.model.HSLFShape; +import org.apache.poi.hslf.usermodel.*; import java.io.FileInputStream; @@ -44,12 +40,12 @@ public final class Hyperlinks { //read hyperlinks from the slide's text runs System.out.println("reading hyperlinks from the text runs"); - HSLFTextParagraph[] txt = slide[j].getTextRuns(); + HSLFTextParagraph[] txt = slide[j].getTextParagraphs(); for (int k = 0; k < txt.length; k++) { - String text = txt[k].getText(); - Hyperlink[] links = txt[k].getHyperlinks(); + String text = txt[k].getRawText(); + HSLFHyperlink[] links = txt[k].getHyperlinks(); if(links != null) for (int l = 0; l < links.length; l++) { - Hyperlink link = links[l]; + HSLFHyperlink link = links[l]; String title = link.getTitle(); String address = link.getAddress(); System.out.println(" " + title); @@ -65,7 +61,7 @@ public final class Hyperlinks { System.out.println(" reading hyperlinks from the slide's shapes"); HSLFShape[] sh = slide[j].getShapes(); for (int k = 0; k < sh.length; k++) { - Hyperlink link = sh[k].getHyperlink(); + HSLFHyperlink link = sh[k].getHyperlink(); if(link != null) { String title = link.getTitle(); String address = link.getAddress(); diff --git a/src/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java b/src/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java index 373f942844..784d912c0e 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java +++ b/src/examples/src/org/apache/poi/hslf/examples/PPT2PNG.java @@ -21,6 +21,7 @@ import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.model.*; import javax.imageio.ImageIO; + import java.io.FileOutputStream; import java.io.FileInputStream; import java.awt.*; diff --git a/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java b/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java index 765ba3ef49..7ebbea9f17 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java +++ b/src/examples/src/org/apache/poi/hslf/examples/SoundFinder.java @@ -21,6 +21,7 @@ import org.apache.poi.hslf.record.InteractiveInfo; import org.apache.poi.hslf.record.InteractiveInfoAtom; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.usermodel.*; + import java.io.FileInputStream; import java.util.Iterator; import java.util.List; diff --git a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java index 5dd1edea06..1d03e1b6f1 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java +++ b/src/examples/src/org/apache/poi/hslf/examples/TableDemo.java @@ -17,8 +17,7 @@ package org.apache.poi.hslf.examples; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFTextRun; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.model.*; import java.awt.*; @@ -53,7 +52,7 @@ public final class TableDemo { for (int j = 0; j < txt1[i].length; j++) { TableCell cell = table1.getCell(i, j); cell.setText(txt1[i][j]); - HSLFTextRun rt = cell.getTextParagraph().getRichTextRuns()[0]; + HSLFTextRun rt = cell.getTextParagraphs().getTextRuns()[0]; rt.setFontName("Arial"); rt.setFontSize(10); if(i == 0){ @@ -92,7 +91,7 @@ public final class TableDemo { for (int j = 0; j < txt2[i].length; j++) { TableCell cell = table2.getCell(i, j); cell.setText(txt2[i][j]); - HSLFTextRun rt = cell.getTextParagraph().getRichTextRuns()[0]; + HSLFTextRun rt = cell.getTextParagraphs().getTextRuns()[0]; rt.setFontSize(10); rt.setFontName("Arial"); if(i == 0){ diff --git a/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmeddedObjects.java b/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmeddedObjects.java index caf96a84c8..c656e7c5c6 100644 --- a/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmeddedObjects.java +++ b/src/examples/src/org/apache/poi/hssf/usermodel/examples/EmeddedObjects.java @@ -21,8 +21,8 @@ import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.Entry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.hwpf.HWPFDocument; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import java.io.FileInputStream; import java.util.Iterator; diff --git a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java index a83a17e4b8..2f0e7e7515 100644 --- a/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java +++ b/src/examples/src/org/apache/poi/xslf/usermodel/tutorial/Step1.java @@ -52,10 +52,10 @@ public class Step1 { for(XSLFTextParagraph p : tsh){ System.out.println("Paragraph level: " + p.getLevel()); for(XSLFTextRun r : p){ - System.out.println(r.getText()); + System.out.println(r.getRawText()); System.out.println(" bold: " + r.isBold()); System.out.println(" italic: " + r.isItalic()); - System.out.println(" underline: " + r.isUnderline()); + System.out.println(" underline: " + r.isUnderlined()); System.out.println(" font.family: " + r.getFontFamily()); System.out.println(" font.size: " + r.getFontSize()); System.out.println(" font.color: " + r.getFontColor()); diff --git a/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java b/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java index ea3a5b28e1..69b570f7d3 100644 --- a/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java +++ b/src/examples/src/org/apache/poi/xssf/usermodel/examples/EmbeddedObjects.java @@ -20,7 +20,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xwpf.usermodel.XWPFDocument; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.xslf.XSLFSlideShow; import org.apache.poi.hssf.usermodel.HSSFWorkbook; diff --git a/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java b/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java index 6b2ee5f09e..a946b18c12 100644 --- a/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java +++ b/src/integrationtest/org/apache/poi/stress/HSLFFileHandler.java @@ -22,8 +22,8 @@ import static org.junit.Assert.assertTrue; import java.io.FileInputStream; import java.io.InputStream; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.Record; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.junit.Test; public class HSLFFileHandler extends POIFSFileHandler { diff --git a/src/java/org/apache/poi/ddf/EscherContainerRecord.java b/src/java/org/apache/poi/ddf/EscherContainerRecord.java index 8454231cf1..d6139436aa 100644 --- a/src/java/org/apache/poi/ddf/EscherContainerRecord.java +++ b/src/java/org/apache/poi/ddf/EscherContainerRecord.java @@ -18,10 +18,7 @@ package org.apache.poi.ddf; import java.io.PrintWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.NoSuchElementException; +import java.util.*; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; @@ -154,30 +151,9 @@ public final class EscherContainerRecord extends EscherRecord { } public Iterator getChildIterator() { - return new ReadOnlyIterator(_childRecords); + return Collections.unmodifiableList(_childRecords).iterator(); } - private static final class ReadOnlyIterator implements Iterator { - private final List _list; - private int _index; - public ReadOnlyIterator(List list) { - _list = list; - _index = 0; - } - - public boolean hasNext() { - return _index < _list.size(); - } - public EscherRecord next() { - if (!hasNext()) { - throw new NoSuchElementException(); - } - return _list.get(_index++); - } - public void remove() { - throw new UnsupportedOperationException(); - } - } /** * replaces the internal child list with the contents of the supplied childRecords */ diff --git a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java index 67f1067b71..266ebb395d 100644 --- a/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java +++ b/src/ooxml/java/org/apache/poi/xslf/extractor/XSLFPowerPointExtractor.java @@ -17,6 +17,7 @@ package org.apache.poi.xslf.extractor; import java.io.IOException; +import java.util.List; import org.apache.poi.POIXMLTextExtractor; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; @@ -122,7 +123,7 @@ public class XSLFPowerPointExtractor extends POIXMLTextExtractor { public String getText(boolean slideText, boolean notesText, boolean masterText) { StringBuffer text = new StringBuffer(); - XSLFSlide[] slides = slideshow.getSlides(); + List slides = slideshow.getSlides(); XSLFCommentAuthors commentAuthors = slideshow.getCommentAuthors(); for (XSLFSlide slide : slides) { diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java index 26780f9662..6bdca81d6f 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XMLSlideShow.java @@ -17,52 +17,20 @@ package org.apache.poi.xslf.usermodel; import java.awt.Dimension; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.io.*; +import java.util.*; import java.util.regex.Pattern; -import org.apache.poi.POIXMLDocument; -import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.POIXMLException; -import org.apache.poi.POIXMLRelation; +import org.apache.poi.*; import org.apache.poi.openxml4j.exceptions.OpenXML4JException; -import org.apache.poi.openxml4j.opc.OPCPackage; -import org.apache.poi.openxml4j.opc.PackagePart; -import org.apache.poi.openxml4j.opc.PackagePartName; -import org.apache.poi.openxml4j.opc.TargetMode; -import org.apache.poi.sl.usermodel.MasterSheet; -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.IOUtils; -import org.apache.poi.util.Internal; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.PackageHelper; -import org.apache.poi.util.Units; +import org.apache.poi.openxml4j.opc.*; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.util.*; import org.apache.poi.xslf.XSLFSlideShow; -import org.apache.xmlbeans.XmlException; -import org.apache.xmlbeans.XmlObject; -import org.apache.xmlbeans.XmlOptions; +import org.apache.xmlbeans.*; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties; import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; -import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdList; -import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdListEntry; -import org.openxmlformats.schemas.presentationml.x2006.main.CTPresentation; -import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdList; -import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry; -import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideSize; -import org.openxmlformats.schemas.presentationml.x2006.main.PresentationDocument; - -import sun.reflect.generics.reflectiveObjects.NotImplementedException; - -import com.sun.org.apache.xml.internal.utils.UnImplNode; +import org.openxmlformats.schemas.presentationml.x2006.main.*; /** * High level representation of a ooxml slideshow. @@ -334,7 +302,7 @@ public class XMLSlideShow extends POIXMLDocument implements SlideShow { XSLFTheme theme = (XSLFTheme) createRelationship(XSLFRelation.THEME, XSLFFactory.getInstance(), themeIndex); - theme.importTheme(getSlides()[0].getTheme()); + theme.importTheme(getSlides().get(0).getTheme()); _notesMaster.addRelation(theme.getPackageRelationship().getId(), theme); PackagePartName themePackagePartName = theme.getPackagePart().getPartName(); @@ -350,15 +318,16 @@ public class XMLSlideShow extends POIXMLDocument implements SlideShow { return _notesMaster; } - public XSLFSlideMaster[] getSlideMasters() { - return _masters.values().toArray(new XSLFSlideMaster[_masters.size()]); + @Override + public List getSlideMasters() { + return new ArrayList(_masters.values()); } /** * Return all the slides in the slideshow */ - public XSLFSlide[] getSlides() { - return _slides.toArray(new XSLFSlide[_slides.size()]); + public List getSlides() { + return _slides; } /** @@ -496,10 +465,6 @@ public class XMLSlideShow extends POIXMLDocument implements SlideShow { return null; } - public XSLFSlideMaster[] getMasterSheet() { - return getSlideMasters(); - } - public MasterSheet createMasterSheet() throws IOException { // TODO: implement! throw new UnsupportedOperationException(); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java index 9a58a5128a..685ae46da5 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFGroupShape.java @@ -27,8 +27,7 @@ import java.util.regex.Pattern; import org.apache.poi.openxml4j.opc.*; import org.apache.poi.sl.usermodel.PlaceableShape; import org.apache.poi.sl.usermodel.ShapeGroup; -import org.apache.poi.util.Beta; -import org.apache.poi.util.Units; +import org.apache.poi.util.*; import org.apache.xmlbeans.XmlObject; import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.openxmlformats.schemas.presentationml.x2006.main.*; @@ -40,6 +39,8 @@ import org.openxmlformats.schemas.presentationml.x2006.main.*; */ @Beta public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, ShapeGroup { + private static POILogger _logger = POILogFactory.getLogger(XSLFGroupShape.class); + private final List _shapes; private final CTGroupShapeProperties _grpSpPr; private XSLFDrawing _drawing; @@ -135,8 +136,9 @@ public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, Sha * * @return child shapes contained witin this group */ - public XSLFShape[] getShapes(){ - return _shapes.toArray(new XSLFShape[_shapes.size()]); + @Override + public List getShapes(){ + return _shapes; } /** @@ -246,6 +248,13 @@ public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, Sha return sh; } + public XSLFTable createTable(){ + XSLFTable sh = getDrawing().createTable(); + _shapes.add(sh); + sh.setParent(this); + return sh; + } + @Override public void setFlipHorizontal(boolean flip){ getSafeXfrm().setFlipH(flip); @@ -282,14 +291,36 @@ public class XSLFGroupShape extends XSLFShape implements XSLFShapeContainer, Sha @Override void copy(XSLFShape src){ XSLFGroupShape gr = (XSLFGroupShape)src; + + // clear shapes + clear(); + // recursively update each shape - XSLFShape[] tgtShapes = getShapes(); - XSLFShape[] srcShapes = gr.getShapes(); - for(int i = 0; i < tgtShapes.length; i++){ - XSLFShape s1 = srcShapes[i]; - XSLFShape s2 = tgtShapes[i]; - - s2.copy(s1); + for(XSLFShape shape : gr.getShapes()) { + XSLFShape newShape = null; + if (shape instanceof XSLFTextBox) { + newShape = createTextBox(); + } else if (shape instanceof XSLFAutoShape) { + newShape = createAutoShape(); + } else if (shape instanceof XSLFConnectorShape) { + newShape = createConnector(); + } else if (shape instanceof XSLFFreeformShape) { + newShape = createFreeform(); + } else if (shape instanceof XSLFPictureShape) { + XSLFPictureShape p = (XSLFPictureShape)shape; + XSLFPictureData pd = p.getPictureData(); + int picId = getSheet().getSlideShow().addPicture(pd.getData(), pd.getPictureType()); + newShape = createPicture(picId); + } else if (shape instanceof XSLFGroupShape) { + newShape = createGroup(); + } else if (shape instanceof XSLFTable) { + newShape = createTable(); + } else { + _logger.log(POILogger.WARN, "copying of class "+shape.getClass()+" not supported."); + continue; + } + + newShape.copy(shape); } } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java index a953e2013e..7296d1d450 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFNotes.java @@ -91,12 +91,12 @@ public final class XSLFNotes extends XSLFSheet implements Notes getTextParagraphs() { - List tp = new ArrayList(); + public List> getTextParagraphs() { + List> tp = new ArrayList>(); for (XSLFShape sh : super.getShapes()) { if (sh instanceof XSLFTextShape) { XSLFTextShape txt = (XSLFTextShape)sh; - tp.addAll(txt.getTextParagraphs()); + tp.add(txt.getTextParagraphs()); } } return tp; diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java index 38dea1b462..43ec701301 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSheet.java @@ -199,8 +199,8 @@ public abstract class XSLFSheet extends POIXMLDocumentPart implements XSLFShapeC * * @return an array of all shapes in this sheet */ - public XSLFShape[] getShapes(){ - return getShapeList().toArray(new XSLFShape[_shapes.size()]); + public List getShapes(){ + return getShapeList(); } /** @@ -301,6 +301,9 @@ public abstract class XSLFSheet extends POIXMLDocumentPart implements XSLFShapeC _spTree = null; _placeholders = null; + // fix-me: wth would this ever happen to work ... + + // first copy the source xml getSpTree().set(src.getSpTree()); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java index ee62ee9d79..b6ee1bc8e2 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFSlide.java @@ -29,7 +29,7 @@ import org.openxmlformats.schemas.drawingml.x2006.main.*; import org.openxmlformats.schemas.presentationml.x2006.main.*; @Beta -public final class XSLFSlide extends XSLFSheet implements Slide { +public final class XSLFSlide extends XSLFSheet implements Slide { private final CTSlide _slide; private XSLFSlideLayout _layout; private XSLFComments _comments; @@ -245,7 +245,7 @@ public final class XSLFSlide extends XSLFSheet implements Slide notes) { + public void setNotes(XSLFNotes notes) { // TODO Auto-generated method stub } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java index 6f6dad8ee8..ca369ea957 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextParagraph.java @@ -68,7 +68,7 @@ public class XSLFTextParagraph implements TextParagraph { public String getText(){ StringBuilder out = new StringBuilder(); for (XSLFTextRun r : _runs) { - out.append(r.getText()); + out.append(r.getRawText()); } return out.toString(); } @@ -171,6 +171,39 @@ public class XSLFTextParagraph implements TextParagraph { } } + @Override + public FontAlign getFontAlign(){ + ParagraphPropertyFetcher fetcher = new ParagraphPropertyFetcher(getLevel()){ + public boolean fetch(CTTextParagraphProperties props){ + if(props.isSetFontAlgn()){ + FontAlign val = FontAlign.values()[props.getFontAlgn().intValue() - 1]; + setValue(val); + return true; + } + return false; + } + }; + fetchParagraphProperty(fetcher); + return fetcher.getValue() == null ? FontAlign.AUTO : fetcher.getValue(); + } + + /** + * Specifies the font alignment that is to be applied to the paragraph. + * Possible values for this include auto, top, center, baseline and bottom. + * see {@link org.apache.poi.sl.usermodel.TextParagraph.FontAlign}. + * + * @param align font align + */ + public void setFontAlign(FontAlign align){ + CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); + if(align == null) { + if(pr.isSetFontAlgn()) pr.unsetFontAlgn(); + } else { + pr.setFontAlgn(STTextFontAlignType.Enum.forInt(align.ordinal() + 1)); + } + } + + /** * @return the font to be used on bullet characters within a given paragraph @@ -306,6 +339,7 @@ public class XSLFTextParagraph implements TextParagraph { * * @param value the indent in points. */ + @Override public void setIndent(double value){ CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); if(value == -1) { @@ -319,6 +353,7 @@ public class XSLFTextParagraph implements TextParagraph { * * @return the indent applied to the first line of text in the paragraph. */ + @Override public double getIndent(){ ParagraphPropertyFetcher fetcher = new ParagraphPropertyFetcher(getLevel()){ @@ -340,8 +375,9 @@ public class XSLFTextParagraph implements TextParagraph { * inset and applies only to this text paragraph. That is the text body Inset and the LeftMargin * attributes are additive with respect to the text position. * - * @param value the left margin of the paragraph + * @param value the left margin (in points) of the paragraph */ + @Override public void setLeftMargin(double value){ CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); if(value == -1) { @@ -353,9 +389,9 @@ public class XSLFTextParagraph implements TextParagraph { } /** - * - * @return the left margin of the paragraph + * @return the left margin (in points) of the paragraph */ + @Override public double getLeftMargin(){ ParagraphPropertyFetcher fetcher = new ParagraphPropertyFetcher(getLevel()){ public boolean fetch(CTTextParagraphProperties props){ @@ -372,10 +408,28 @@ public class XSLFTextParagraph implements TextParagraph { return fetcher.getValue() == null ? 0 : fetcher.getValue(); } + /** + * Specifies the right margin of the paragraph. This is specified in addition to the text body + * inset and applies only to this text paragraph. That is the text body Inset and the RightMargin + * attributes are additive with respect to the text position. + * + * @param value the right margin (in points) of the paragraph + */ + @Override + public void setRightMargin(double value){ + CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr(); + if(value == -1) { + if(pr.isSetMarR()) pr.unsetMarR(); + } else { + pr.setMarR(Units.toEMU(value)); + } + } + /** * * @return the right margin of the paragraph */ + @Override public double getRightMargin(){ ParagraphPropertyFetcher fetcher = new ParagraphPropertyFetcher(getLevel()){ public boolean fetch(CTTextParagraphProperties props){ @@ -834,11 +888,13 @@ public class XSLFTextParagraph implements TextParagraph { } } + @Override public double getDefaultFontSize() { CTTextCharacterProperties endPr = _p.getEndParaRPr(); return (endPr == null || !endPr.isSetSz()) ? 12 : (endPr.getSz() / 100); } + @Override public String getDefaultFontFamily() { return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily()); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index 0a6daf6cea..2b63a58099 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -59,7 +59,7 @@ public class XSLFTextRun implements TextRun { return _p; } - public String getText(){ + public String getRawText(){ return _r.getT(); } @@ -479,7 +479,7 @@ public class XSLFTextRun implements TextRun { /** * @return whether this run of text is formatted as underlined text */ - public boolean isUnderline(){ + public boolean isUnderlined(){ CharacterPropertyFetcher fetcher = new CharacterPropertyFetcher(_p.getLevel()){ public boolean fetch(CTTextCharacterProperties props){ if(props.isSetU()){ @@ -499,7 +499,7 @@ public class XSLFTextRun implements TextRun { @Override public String toString(){ - return "[" + getClass() + "]" + getText(); + return "[" + getClass() + "]" + getRawText(); } public XSLFHyperlink createHyperlink(){ @@ -568,8 +568,8 @@ public class XSLFTextRun implements TextRun { boolean italic = r.isItalic(); if(italic != isItalic()) setItalic(italic); - boolean underline = r.isUnderline(); - if(underline != isUnderline()) setUnderline(underline); + boolean underline = r.isUnderlined(); + if(underline != isUnderlined()) setUnderline(underline); boolean strike = r.isStrikethrough(); if(strike != isStrikethrough()) setStrikethrough(strike); diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java index ac482a981f..5b58adbf1a 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextShape.java @@ -112,7 +112,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape * Sets the type of vertical alignment for the text. * * @param anchor - the type of alignment. - * A null values unsets this property. + * A {@code null} values unsets this property. */ public void setVerticalAlignment(VerticalAlignment anchor){ CTTextBodyProperties bodyPr = getTextBodyPr(); @@ -145,6 +145,40 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape 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() + */ + public void setHorizontalCentered(Boolean isCentered){ + CTTextBodyProperties bodyPr = getTextBodyPr(); + if (bodyPr != null) { + if (isCentered == null) { + if (bodyPr.isSetAnchorCtr()) bodyPr.unsetAnchorCtr(); + } else { + bodyPr.setAnchorCtr(isCentered); + } + } + } + + @Override + public boolean isHorizontalCentered(){ + PropertyFetcher fetcher = new TextBodyPropertyFetcher(){ + public boolean fetch(CTTextBodyProperties props){ + if(props.isSetAnchorCtr()){ + setValue(props.getAnchorCtr()); + return true; + } + return false; + } + }; + fetchShapeProperty(fetcher); + return fetcher.getValue() == null ? false : fetcher.getValue(); + } + /** * * @param orientation vertical orientation of the text @@ -266,7 +300,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape } /** - * Sets the botom margin. + * Sets the bottom margin. * @see #getBottomInset() * * @param margin the bottom margin @@ -429,9 +463,7 @@ public abstract class XSLFTextShape extends XSLFSimpleShape implements TextShape } } - /** - * Compute the cumulative height occupied by the text - */ + @Override public double getTextHeight(){ DrawFactory drawFact = DrawFactory.getInstance(null); DrawTextShape dts = drawFact.getDrawable(this); diff --git a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java index 76bb08559f..400c637ca8 100644 --- a/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java +++ b/src/ooxml/java/org/apache/poi/xslf/util/PPTX2PNG.java @@ -24,12 +24,14 @@ import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.poi.xslf.usermodel.XSLFSlide; import javax.imageio.ImageIO; + import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.FileOutputStream; +import java.util.List; /** * An utulity to convert slides of a .pptx slide show to a PNG image @@ -79,11 +81,11 @@ public class PPTX2PNG { int width = (int) (pgsize.width * scale); int height = (int) (pgsize.height * scale); - XSLFSlide[] slide = ppt.getSlides(); - for (int i = 0; i < slide.length; i++) { + List slide = ppt.getSlides(); + for (int i = 0; i < slide.size(); i++) { if (slidenum != -1 && slidenum != (i + 1)) continue; - String title = slide[i].getTitle(); + String title = slide.get(i).getTitle(); System.out.println("Rendering slide " + (i + 1) + (title == null ? "" : ": " + title)); BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); @@ -101,7 +103,7 @@ public class PPTX2PNG { graphics.scale(scale, scale); // draw stuff - slide[i].draw(graphics); + slide.get(i).draw(graphics); // save the result int sep = file.lastIndexOf("."); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java index 7d18541d9b..6d66caefe0 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/TestXSLFBugs.java @@ -55,8 +55,8 @@ public class TestXSLFBugs { public void bug51187() throws Exception { XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("51187.pptx"); - assertEquals(1, ss.getSlides().length); - XSLFSlide slide = ss.getSlides()[0]; + assertEquals(1, ss.getSlides().size()); + XSLFSlide slide = ss.getSlides().get(0); // Check the relations on it // Note - rId3 is a self reference @@ -71,7 +71,7 @@ public class TestXSLFBugs { // Save and re-load ss = XSLFTestDataSamples.writeOutAndReadBack(ss); - assertEquals(1, ss.getSlides().length); + assertEquals(1, ss.getSlides().size()); slidePart = ss._getXSLFSlideShow().getSlidePart( ss._getXSLFSlideShow().getSlideReferences().getSldIdArray(0) @@ -92,8 +92,8 @@ public class TestXSLFBugs { XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("with_japanese.pptx"); // Should have one slide - assertEquals(1, ss.getSlides().length); - XSLFSlide slide = ss.getSlides()[0]; + assertEquals(1, ss.getSlides().size()); + XSLFSlide slide = ss.getSlides().get(0); // Check the relations from this List rels = slide.getRelations(); @@ -142,20 +142,20 @@ public class TestXSLFBugs { XSLFSlide slide; // Should find 4 slides - assertEquals(4, ss.getSlides().length); + assertEquals(4, ss.getSlides().size()); // Check the text, to see we got them in order - slide = ss.getSlides()[0]; + slide = ss.getSlides().get(0); assertContains("POI cannot read this", getSlideText(slide)); - slide = ss.getSlides()[1]; + slide = ss.getSlides().get(1); assertContains("POI can read this", getSlideText(slide)); assertContains("Has a relationship to another slide", getSlideText(slide)); - slide = ss.getSlides()[2]; + slide = ss.getSlides().get(2); assertContains("POI can read this", getSlideText(slide)); - slide = ss.getSlides()[3]; + slide = ss.getSlides().get(3); assertContains("POI can read this", getSlideText(slide)); } @@ -196,13 +196,13 @@ public class TestXSLFBugs { } @Test - @Ignore("Similar to TestFontRendering it doesn't make sense to compare images because of tiny rendering differences in windows/unix") + // @Ignore("Similar to TestFontRendering it doesn't make sense to compare images because of tiny rendering differences in windows/unix") public void bug54542() throws Exception { XMLSlideShow ss = XSLFTestDataSamples.openSampleDocument("54542_cropped_bitmap.pptx"); Dimension pgsize = ss.getPageSize(); - XSLFSlide slide = ss.getSlides()[0]; + XSLFSlide slide = ss.getSlides().get(0); // render it double zoom = 1; @@ -265,10 +265,10 @@ public class TestXSLFBugs { ss = XSLFTestDataSamples.writeOutAndReadBack(ss); } - assertEquals(slideTexts.length, ss.getSlides().length); + assertEquals(slideTexts.length, ss.getSlides().size()); for (int i = 0; i < slideTexts.length; i++) { - XSLFSlide slide = ss.getSlides()[i]; + XSLFSlide slide = ss.getSlides().get(i); assertContains(getSlideText(slide), slideTexts[i]); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java index 47d2277712..36d42471ca 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestFormulaParser.java @@ -18,19 +18,19 @@ */ package org.apache.poi.xslf.geom; -import junit.framework.TestCase; -import org.apache.poi.xslf.model.geom.Context; -import org.apache.poi.xslf.model.geom.CustomGeometry; -import org.apache.poi.xslf.model.geom.Formula; -import org.apache.poi.xslf.model.geom.Guide; -import org.openxmlformats.schemas.drawingml.x2006.main.CTCustomGeometry2D; +import static org.junit.Assert.assertEquals; + +import org.apache.poi.sl.draw.binding.CTCustomGeometry2D; +import org.apache.poi.sl.draw.geom.*; +import org.junit.Test; /** * Date: 10/24/11 * * @author Yegor Kozlov */ -public class TestFormulaParser extends TestCase { +public class TestFormulaParser { + @Test public void testParse(){ Formula[] ops = { @@ -44,18 +44,18 @@ public class TestFormulaParser extends TestCase { new Guide("a5", "abs -2"), }; - CustomGeometry geom = new CustomGeometry(CTCustomGeometry2D.Factory.newInstance()); + CustomGeometry geom = new CustomGeometry(new CTCustomGeometry2D()); Context ctx = new Context(geom, null, null); for(Formula fmla : ops) { ctx.evaluate(fmla); } - assertEquals(100.0, ctx.getValue("adj1")); - assertEquals(200.0, ctx.getValue("adj2")); - assertEquals(1.0, ctx.getValue("a1")); - assertEquals(101.0, ctx.getValue("a2")); - assertEquals(1.5, ctx.getValue("a3")); - assertEquals(200.0, ctx.getValue("a4")); - assertEquals(2.0, ctx.getValue("a5")); + assertEquals(100.0, ctx.getValue("adj1"), 0.0); + assertEquals(200.0, ctx.getValue("adj2"), 0.0); + assertEquals(1.0, ctx.getValue("a1"), 0.0); + assertEquals(101.0, ctx.getValue("a2"), 0.0); + assertEquals(1.5, ctx.getValue("a3"), 0.0); + assertEquals(200.0, ctx.getValue("a4"), 0.0); + assertEquals(2.0, ctx.getValue("a5"), 0.0); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java index 50a66667ab..5001dc8b91 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/geom/TestPresetGeometries.java @@ -18,24 +18,23 @@ */ package org.apache.poi.xslf.geom; -import junit.framework.TestCase; -import org.apache.poi.xslf.model.geom.Context; -import org.apache.poi.xslf.model.geom.CustomGeometry; -import org.apache.poi.xslf.model.geom.Guide; -import org.apache.poi.xslf.model.geom.IAdjustableShape; -import org.apache.poi.xslf.model.geom.Path; -import org.apache.poi.xslf.model.geom.PresetGeometries; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.util.Map; +import org.apache.poi.sl.draw.geom.*; +import org.junit.Test; + /** * Date: 10/24/11 * * @author Yegor Kozlov */ -public class TestPresetGeometries extends TestCase { +public class TestPresetGeometries { + @Test public void testRead(){ Map shapes = PresetGeometries.getInstance(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java index 5c616cd43a..e2124eca3b 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestPPTX2PNG.java @@ -25,7 +25,7 @@ import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.Map; -import org.apache.poi.hslf.model.TextPainter; +import org.apache.poi.sl.draw.Drawable; import org.apache.poi.util.JvmBugs; import org.apache.poi.xslf.XSLFTestDataSamples; import org.junit.Test; @@ -56,10 +56,10 @@ public class TestPPTX2PNG { @SuppressWarnings("unchecked") private void fixFonts(Graphics2D graphics) { if (!JvmBugs.hasLineBreakMeasurerBug()) return; - Map fontMap = (Map)graphics.getRenderingHint(TextPainter.KEY_FONTMAP); + Map fontMap = (Map)graphics.getRenderingHint(Drawable.FONT_MAP); if (fontMap == null) fontMap = new HashMap(); fontMap.put("Calibri", "Lucida Sans"); fontMap.put("Cambria", "Lucida Bright"); - graphics.setRenderingHint(TextPainter.KEY_FONTMAP, fontMap); + graphics.setRenderingHint(Drawable.FONT_MAP, fontMap); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java index 604f68fffb..5b615ee828 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXMLSlideShow.java @@ -16,23 +16,25 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.*; import org.apache.poi.POIDataSamples; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackagePart; -import org.openxmlformats.schemas.presentationml.x2006.main.CTNotesMasterIdListEntry; -import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideIdListEntry; -import org.openxmlformats.schemas.presentationml.x2006.main.CTSlideMasterIdListEntry; +import org.junit.Before; +import org.junit.Test; +import org.openxmlformats.schemas.presentationml.x2006.main.*; -public class TestXMLSlideShow extends TestCase { +public class TestXMLSlideShow { private static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); private OPCPackage pack; - protected void setUp() throws Exception { + @Before + public void setUp() throws Exception { pack = OPCPackage.open(slTests.openResourceAsStream("sample.pptx")); } + @Test public void testContainsMainContentType() throws Exception { boolean found = false; for(PackagePart part : pack.getParts()) { @@ -43,6 +45,7 @@ public class TestXMLSlideShow extends TestCase { assertTrue(found); } + @Test public void testOpen() throws Exception { XMLSlideShow xml; @@ -52,22 +55,20 @@ public class TestXMLSlideShow extends TestCase { assertNotNull(xml.getCTPresentation()); // Check it has some slides - assertNotNull(xml.getSlides().length); - assertTrue(xml.getSlides().length > 0); - - assertNotNull(xml.getSlideMasters().length); - assertTrue(xml.getSlideMasters().length > 0); + assertFalse(xml.getSlides().isEmpty()); + assertFalse(xml.getSlideMasters().isEmpty()); } + @Test @SuppressWarnings("deprecation") public void testSlideBasics() throws Exception { XMLSlideShow xml = new XMLSlideShow(pack); // Should have 1 master - assertEquals(1, xml.getSlideMasters().length); + assertEquals(1, xml.getSlideMasters().size()); // Should have two sheets - assertEquals(2, xml.getSlides().length); + assertEquals(2, xml.getSlides().size()); // Check they're as expected CTSlideIdListEntry[] slides = xml.getCTPresentation().getSldIdLst().getSldIdArray(); @@ -78,19 +79,19 @@ public class TestXMLSlideShow extends TestCase { assertEquals("rId3", slides[1].getId2()); // Now get those objects - assertNotNull(xml.getSlides()[0]); - assertNotNull(xml.getSlides()[1]); + assertNotNull(xml.getSlides().get(0)); + assertNotNull(xml.getSlides().get(1)); // And check they have notes as expected - assertNotNull(xml.getSlides()[0].getNotes()); - assertNotNull(xml.getSlides()[1].getNotes()); + assertNotNull(xml.getSlides().get(0).getNotes()); + assertNotNull(xml.getSlides().get(1).getNotes()); // Next up look for the slide master CTSlideMasterIdListEntry[] masters = xml.getCTPresentation().getSldMasterIdLst().getSldMasterIdArray(); assertEquals(2147483648l, masters[0].getId()); assertEquals("rId1", masters[0].getId2()); - assertNotNull(xml.getSlideMasters()[0]); + assertNotNull(xml.getSlideMasters().get(0)); // Finally look for the notes master CTNotesMasterIdListEntry notesMaster = @@ -100,6 +101,7 @@ public class TestXMLSlideShow extends TestCase { assertNotNull(xml.getNotesMaster()); } + @Test public void testMetadataBasics() throws Exception { XMLSlideShow xml = new XMLSlideShow(pack); @@ -114,6 +116,7 @@ public class TestXMLSlideShow extends TestCase { assertEquals(null, xml.getProperties().getCoreProperties().getUnderlyingProperties().getSubjectProperty().getValue()); } + @Test public void testComments() throws Exception { // Default sample file has none XMLSlideShow xml = new XMLSlideShow(pack); @@ -134,8 +137,9 @@ public class TestXMLSlideShow extends TestCase { assertEquals("XPVMWARE01", xmlComments.getCommentAuthors().getAuthorById(0).getName()); // First two slides have comments - for (int i=0; i shapes = slide.getShapes(); + XSLFTable tbl = (XSLFTable)shapes.get(0); XSLFTableCell cell1 = tbl.getRows().get(1).getCells().get(0); assertEquals("Web Page", cell1.getText()); XSLFHyperlink link1 = cell1.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink(); @@ -53,6 +58,7 @@ public class TestXSLFHyperlink extends TestCase { assertEquals(URI.create("mailto:dev@poi.apache.org?subject=Hi%20There"), link3.getTargetURI()); } + @Test public void testCreate() throws Exception { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide1 = ppt.createSlide(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFPictureShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFPictureShape.java index 955b273c1e..0ec9b972a0 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFPictureShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFPictureShape.java @@ -16,22 +16,20 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.*; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import junit.framework.TestCase; +import java.util.*; import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; import org.openxmlformats.schemas.presentationml.x2006.main.CTPicture; /** * @author Yegor Kozlov */ -public class TestXSLFPictureShape extends TestCase { +public class TestXSLFPictureShape { + @Test public void testCreate() { XMLSlideShow ppt = new XMLSlideShow(); assertEquals(0, ppt.getAllPictures().size()); @@ -61,11 +59,12 @@ public class TestXSLFPictureShape extends TestCase { assertArrayEquals(data1, pics.get(0).getData()); assertArrayEquals(data2, pics.get(1).getData()); - XSLFShape[] shapes = ppt.getSlides()[0].getShapes(); - assertArrayEquals(data1, ((XSLFPictureShape) shapes[0]).getPictureData().getData()); - assertArrayEquals(data2, ((XSLFPictureShape) shapes[1]).getPictureData().getData()); + List shapes = ppt.getSlides().get(0).getShapes(); + assertArrayEquals(data1, ((XSLFPictureShape) shapes.get(0)).getPictureData().getData()); + assertArrayEquals(data2, ((XSLFPictureShape) shapes.get(1)).getPictureData().getData()); } + @Test public void testCreateMultiplePictures() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide1 = ppt.createSlide(); @@ -118,6 +117,7 @@ public class TestXSLFPictureShape extends TestCase { } } + @Test public void testImageCaching() { XMLSlideShow ppt = new XMLSlideShow(); byte[] img1 = new byte[]{1,2,3}; @@ -137,6 +137,7 @@ public class TestXSLFPictureShape extends TestCase { } + @Test public void testMerge() { XMLSlideShow ppt1 = new XMLSlideShow(); byte[] data1 = new byte[100]; @@ -150,7 +151,7 @@ public class TestXSLFPictureShape extends TestCase { XMLSlideShow ppt2 = new XMLSlideShow(); XSLFSlide slide2 = ppt2.createSlide().importContent(slide1); - XSLFPictureShape shape2 = (XSLFPictureShape)slide2.getShapes()[0]; + XSLFPictureShape shape2 = (XSLFPictureShape)slide2.getShapes().get(0); assertArrayEquals(data1, shape2.getPictureData().getData()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShape.java index e6c4728474..3983d0b392 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShape.java @@ -16,8 +16,10 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.*; + import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; import java.util.List; @@ -25,17 +27,18 @@ import java.util.List; /** * @author Yegor Kozlov */ -public class TestXSLFShape extends TestCase { +public class TestXSLFShape { + @Test public void testReadTextShapes() { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); - XSLFSlide[] slides = ppt.getSlides(); + List slides = ppt.getSlides(); - XSLFSlide slide1 = slides[0]; - XSLFShape[] shapes1 = slide1.getShapes(); - assertEquals(7, shapes1.length); - assertEquals("TextBox 3", shapes1[0].getShapeName()); - XSLFAutoShape sh0 = (XSLFAutoShape) shapes1[0]; + XSLFSlide slide1 = slides.get(0); + List shapes1 = slide1.getShapes(); + assertEquals(7, shapes1.size()); + assertEquals("TextBox 3", shapes1.get(0).getShapeName()); + XSLFAutoShape sh0 = (XSLFAutoShape) shapes1.get(0); assertEquals("Learning PPTX", sh0.getText()); List paragraphs0 = sh0.getTextParagraphs(); assertEquals(1, paragraphs0.size()); @@ -43,28 +46,28 @@ public class TestXSLFShape extends TestCase { assertEquals("Learning PPTX", p0.getText()); assertEquals(1, p0.getTextRuns().size()); XSLFTextRun r0 = p0.getTextRuns().get(0); - assertEquals("Learning PPTX", r0.getText()); + assertEquals("Learning PPTX", r0.getRawText()); - XSLFSlide slide2 = slides[1]; - XSLFShape[] shapes2 = slide2.getShapes(); - assertTrue(shapes2[0] instanceof XSLFAutoShape); - assertEquals("PPTX Title", ((XSLFAutoShape) shapes2[0]).getText()); - XSLFAutoShape sh1 = (XSLFAutoShape) shapes2[0]; + XSLFSlide slide2 = slides.get(1); + List shapes2 = slide2.getShapes(); + assertTrue(shapes2.get(0) instanceof XSLFAutoShape); + assertEquals("PPTX Title", ((XSLFAutoShape) shapes2.get(0)).getText()); + XSLFAutoShape sh1 = (XSLFAutoShape) shapes2.get(0); List paragraphs1 = sh1.getTextParagraphs(); assertEquals(1, paragraphs1.size()); XSLFTextParagraph p1 = paragraphs1.get(0); assertEquals("PPTX Title", p1.getText()); List r2 = paragraphs1.get(0).getTextRuns(); assertEquals(2, r2.size()); - assertEquals("PPTX ", r2.get(0).getText()); - assertEquals("Title", r2.get(1).getText()); + assertEquals("PPTX ", r2.get(0).getRawText()); + assertEquals("Title", r2.get(1).getRawText()); // Title is underlined assertEquals(STTextUnderlineType.SNG, r2.get(1).getXmlObject().getRPr().getU()); - assertTrue(shapes2[1] instanceof XSLFAutoShape); - assertEquals("Subtitle\nAnd second line", ((XSLFAutoShape) shapes2[1]).getText()); - XSLFAutoShape sh2 = (XSLFAutoShape) shapes2[1]; + assertTrue(shapes2.get(1) instanceof XSLFAutoShape); + assertEquals("Subtitle\nAnd second line", ((XSLFAutoShape) shapes2.get(1)).getText()); + XSLFAutoShape sh2 = (XSLFAutoShape) shapes2.get(1); List paragraphs2 = sh2.getTextParagraphs(); assertEquals(2, paragraphs2.size()); assertEquals("Subtitle", paragraphs2.get(0).getText()); @@ -73,20 +76,20 @@ public class TestXSLFShape extends TestCase { assertEquals(1, paragraphs2.get(0).getTextRuns().size()); assertEquals(1, paragraphs2.get(1).getTextRuns().size()); - assertEquals("Subtitle", paragraphs2.get(0).getTextRuns().get(0).getText()); + assertEquals("Subtitle", paragraphs2.get(0).getTextRuns().get(0).getRawText()); assertTrue(paragraphs2.get(0).getTextRuns().get(0).getXmlObject().getRPr().getB()); - assertEquals("And second line", paragraphs2.get(1).getTextRuns().get(0).getText()); + assertEquals("And second line", paragraphs2.get(1).getTextRuns().get(0).getRawText()); } public void testCreateShapes() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); - assertEquals(0, slide.getShapes().length); + assertTrue(slide.getShapes().isEmpty()); XSLFTextBox textBox = slide.createTextBox(); - assertEquals(1, slide.getShapes().length); - assertSame(textBox, slide.getShapes()[0]); + assertEquals(1, slide.getShapes().size()); + assertSame(textBox, slide.getShapes().get(0)); assertEquals("", textBox.getText()); assertEquals(0, textBox.getTextParagraphs().size()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShapeContainer.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShapeContainer.java index 8f8e46d944..d880966909 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShapeContainer.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFShapeContainer.java @@ -18,35 +18,40 @@ */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.*; + +import org.junit.Test; /** * test common operations on containers of shapes (sheets and groups of shapes) * * @author Yegor Kozlov */ -public class TestXSLFShapeContainer extends TestCase { +public class TestXSLFShapeContainer { + @SuppressWarnings("unused") + @Test public void verifyContainer(XSLFShapeContainer container) { container.clear(); - assertEquals(0, container.getShapes().length); + assertEquals(0, container.getShapes().size()); XSLFGroupShape shape1 = container.createGroup(); - assertEquals(1, container.getShapes().length); + assertEquals(1, container.getShapes().size()); XSLFTextBox shape2 = container.createTextBox(); - assertEquals(2, container.getShapes().length); + assertEquals(2, container.getShapes().size()); XSLFAutoShape shape3 = container.createAutoShape(); - assertEquals(3, container.getShapes().length); + assertEquals(3, container.getShapes().size()); XSLFConnectorShape shape4 = container.createConnector(); - assertEquals(4, container.getShapes().length); + assertEquals(4, container.getShapes().size()); container.clear(); - assertEquals(0, container.getShapes().length); + assertEquals(0, container.getShapes().size()); } + @Test public void testSheet() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSheet sheet = ppt.createSlide(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSheet.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSheet.java index d605a05198..92c30b62d5 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSheet.java @@ -16,50 +16,56 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.*; + +import java.util.List; + import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; /** * test common properties for sheets (slides, masters, layouts, etc.) * * @author Yegor Kozlov */ -public class TestXSLFSheet extends TestCase { +public class TestXSLFSheet { + + @Test public void testCreateShapes(){ XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); - assertEquals(0, slide.getShapes().length); + assertTrue(slide.getShapes().isEmpty()); XSLFSimpleShape shape1 = slide.createAutoShape(); - assertEquals(1, slide.getShapes().length); - assertSame(shape1, slide.getShapes()[0]); + assertEquals(1, slide.getShapes().size()); + assertSame(shape1, slide.getShapes().get(0)); XSLFTextBox shape2 = slide.createTextBox(); - assertEquals(2, slide.getShapes().length); - assertSame(shape1, slide.getShapes()[0]); - assertSame(shape2, slide.getShapes()[1]); + assertEquals(2, slide.getShapes().size()); + assertSame(shape1, slide.getShapes().get(0)); + assertSame(shape2, slide.getShapes().get(1)); XSLFConnectorShape shape3 = slide.createConnector(); - assertEquals(3, slide.getShapes().length); - assertSame(shape1, slide.getShapes()[0]); - assertSame(shape2, slide.getShapes()[1]); - assertSame(shape3, slide.getShapes()[2]); + assertEquals(3, slide.getShapes().size()); + assertSame(shape1, slide.getShapes().get(0)); + assertSame(shape2, slide.getShapes().get(1)); + assertSame(shape3, slide.getShapes().get(2)); XSLFGroupShape shape4 = slide.createGroup(); - assertEquals(4, slide.getShapes().length); - assertSame(shape1, slide.getShapes()[0]); - assertSame(shape2, slide.getShapes()[1]); - assertSame(shape3, slide.getShapes()[2]); - assertSame(shape4, slide.getShapes()[3]); + assertEquals(4, slide.getShapes().size()); + assertSame(shape1, slide.getShapes().get(0)); + assertSame(shape2, slide.getShapes().get(1)); + assertSame(shape3, slide.getShapes().get(2)); + assertSame(shape4, slide.getShapes().get(3)); ppt = XSLFTestDataSamples.writeOutAndReadBack(ppt); - slide = ppt.getSlides()[0]; - XSLFShape[] shapes = slide.getShapes(); - assertEquals(4, shapes.length); + slide = ppt.getSlides().get(0); + List shapes = slide.getShapes(); + assertEquals(4, shapes.size()); - assertTrue(shapes[0] instanceof XSLFAutoShape); - assertTrue(shapes[1] instanceof XSLFTextBox); - assertTrue(shapes[2] instanceof XSLFConnectorShape); - assertTrue(shapes[3] instanceof XSLFGroupShape); + assertTrue(shapes.get(0) instanceof XSLFAutoShape); + assertTrue(shapes.get(1) instanceof XSLFTextBox); + assertTrue(shapes.get(2) instanceof XSLFConnectorShape); + assertTrue(shapes.get(3) instanceof XSLFGroupShape); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java index b3a5fc211e..064ebe6cb7 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSimpleShape.java @@ -16,30 +16,34 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import java.awt.Color; +import static org.junit.Assert.*; -import junit.framework.TestCase; +import java.awt.Color; +import java.util.List; import org.apache.poi.sl.usermodel.StrokeStyle.LineCap; import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.apache.poi.util.Units; import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.*; /** * @author Yegor Kozlov */ -public class TestXSLFSimpleShape extends TestCase { +public class TestXSLFSimpleShape { + + @Test public void testLineStyles() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); XSLFSimpleShape shape = slide.createAutoShape(); - assertEquals(1, slide.getShapes().length); + assertEquals(1, slide.getShapes().size()); // line properties are not set by default assertFalse(shape.getSpPr().isSetLn()); - assertEquals(0., shape.getLineWidth()); + assertEquals(0., shape.getLineWidth(), 0); assertEquals(null, shape.getLineColor()); assertEquals(null, shape.getLineDash()); assertEquals(null, shape.getLineCap()); @@ -54,10 +58,10 @@ public class TestXSLFSimpleShape extends TestCase { // line width shape.setLineWidth(1.0); - assertEquals(1.0, shape.getLineWidth()); + assertEquals(1.0, shape.getLineWidth(), 0); assertEquals(Units.EMU_PER_POINT, shape.getSpPr().getLn().getW()); shape.setLineWidth(5.5); - assertEquals(5.5, shape.getLineWidth()); + assertEquals(5.5, shape.getLineWidth(), 0); assertEquals(Units.toEMU(5.5), shape.getSpPr().getLn().getW()); shape.setLineWidth(0.0); // setting line width to zero unsets the W attribute @@ -108,17 +112,18 @@ public class TestXSLFSimpleShape extends TestCase { ln2.setLineDash(LineDash.DOT); assertEquals(LineDash.DOT, ln2.getLineDash()); ln2.setLineWidth(0.); - assertEquals(0., ln2.getLineWidth()); + assertEquals(0., ln2.getLineWidth(), 0); XSLFSimpleShape ln3 = slide.createAutoShape(); ln3.setLineWidth(1.); - assertEquals(1., ln3.getLineWidth()); + assertEquals(1., ln3.getLineWidth(), 0); ln3.setLineDash(null); assertEquals(null, ln3.getLineDash()); ln3.setLineCap(null); assertEquals(null, ln3.getLineDash()); } + @Test public void testFill() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -143,29 +148,30 @@ public class TestXSLFSimpleShape extends TestCase { assertFalse(shape.getSpPr().isSetSolidFill()); } + @Test public void testDefaultProperties() { XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); - XSLFSlide slide6 = ppt.getSlides()[5]; - XSLFShape[] shapes = slide6.getShapes(); - for(int i = 1; i < shapes.length; i++){ - XSLFSimpleShape s = (XSLFSimpleShape) shapes[i]; + XSLFSlide slide6 = ppt.getSlides().get(5); + List shapes = slide6.getShapes(); + for(XSLFShape xs : shapes){ + XSLFSimpleShape s = (XSLFSimpleShape)xs; // all shapes have a theme color="accent1" assertEquals("accent1", s.getSpStyle().getFillRef().getSchemeClr().getVal().toString()); - assertEquals(2.0, s.getLineWidth()); + assertEquals(2.0, s.getLineWidth(), 0); assertEquals(LineCap.FLAT, s.getLineCap()); // YK: calculated color is slightly different from PowerPoint assertEquals(new Color(39, 64, 94), s.getLineColor()); } - XSLFSimpleShape s0 = (XSLFSimpleShape) shapes[0]; + XSLFSimpleShape s0 = (XSLFSimpleShape) shapes.get(0); // fill is not set assertNull(s0.getSpPr().getSolidFill()); //assertEquals(slide6.getTheme().getColor("accent1").getColor(), s0.getFillColor()); assertEquals(new Color(79, 129, 189), s0.getFillColor()); // lighter 80% - XSLFSimpleShape s1 = (XSLFSimpleShape)shapes[1]; + XSLFSimpleShape s1 = (XSLFSimpleShape)shapes.get(1); CTSchemeColor ref1 = s1.getSpPr().getSolidFill().getSchemeClr(); assertEquals(1, ref1.sizeOfLumModArray()); assertEquals(1, ref1.sizeOfLumOffArray()); @@ -175,7 +181,7 @@ public class TestXSLFSimpleShape extends TestCase { assertEquals(new Color(220, 230, 242), s1.getFillColor()); // lighter 60% - XSLFSimpleShape s2 = (XSLFSimpleShape)shapes[2]; + XSLFSimpleShape s2 = (XSLFSimpleShape)shapes.get(2); CTSchemeColor ref2 = s2.getSpPr().getSolidFill().getSchemeClr(); assertEquals(1, ref2.sizeOfLumModArray()); assertEquals(1, ref2.sizeOfLumOffArray()); @@ -185,7 +191,7 @@ public class TestXSLFSimpleShape extends TestCase { assertEquals(new Color(185, 205, 229), s2.getFillColor()); // lighter 40% - XSLFSimpleShape s3 = (XSLFSimpleShape)shapes[3]; + XSLFSimpleShape s3 = (XSLFSimpleShape)shapes.get(3); CTSchemeColor ref3 = s3.getSpPr().getSolidFill().getSchemeClr(); assertEquals(1, ref3.sizeOfLumModArray()); assertEquals(1, ref3.sizeOfLumOffArray()); @@ -195,7 +201,7 @@ public class TestXSLFSimpleShape extends TestCase { assertEquals(new Color(149, 179, 215), s3.getFillColor()); // darker 25% - XSLFSimpleShape s4 = (XSLFSimpleShape)shapes[4]; + XSLFSimpleShape s4 = (XSLFSimpleShape)shapes.get(4); CTSchemeColor ref4 = s4.getSpPr().getSolidFill().getSchemeClr(); assertEquals(1, ref4.sizeOfLumModArray()); assertEquals(0, ref4.sizeOfLumOffArray()); @@ -204,7 +210,7 @@ public class TestXSLFSimpleShape extends TestCase { // YK: calculated color is slightly different from PowerPoint assertEquals(new Color(59, 97, 142), s4.getFillColor()); - XSLFSimpleShape s5 = (XSLFSimpleShape)shapes[5]; + XSLFSimpleShape s5 = (XSLFSimpleShape)shapes.get(5); CTSchemeColor ref5 = s5.getSpPr().getSolidFill().getSchemeClr(); assertEquals(1, ref5.sizeOfLumModArray()); assertEquals(0, ref5.sizeOfLumOffArray()); @@ -214,26 +220,27 @@ public class TestXSLFSimpleShape extends TestCase { assertEquals(new Color(40, 65, 95), s5.getFillColor()); } + @Test public void testAnchor(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); - XSLFSlide[] slide = ppt.getSlides(); + List slide = ppt.getSlides(); - XSLFSlide slide2 = slide[1]; + XSLFSlide slide2 = slide.get(1); XSLFSlideLayout layout2 = slide2.getSlideLayout(); - XSLFShape[] shapes2 = slide2.getShapes(); - XSLFTextShape sh1 = (XSLFTextShape)shapes2[0]; + List shapes2 = slide2.getShapes(); + XSLFTextShape sh1 = (XSLFTextShape)shapes2.get(0); assertEquals(Placeholder.CENTERED_TITLE, sh1.getTextType()); assertEquals("PPTX Title", sh1.getText()); assertNull(sh1.getSpPr().getXfrm()); // xfrm is not set, the query is delegated to the slide layout assertEquals(sh1.getAnchor(), layout2.getTextShapeByType(Placeholder.CENTERED_TITLE).getAnchor()); - XSLFTextShape sh2 = (XSLFTextShape)shapes2[1]; + XSLFTextShape sh2 = (XSLFTextShape)shapes2.get(1); assertEquals("Subtitle\nAnd second line", sh2.getText()); assertEquals(Placeholder.SUBTITLE, sh2.getTextType()); assertNull(sh2.getSpPr().getXfrm()); // xfrm is not set, the query is delegated to the slide layout assertEquals(sh2.getAnchor(), layout2.getTextShapeByType(Placeholder.SUBTITLE).getAnchor()); - XSLFSlide slide5 = slide[4]; + XSLFSlide slide5 = slide.get(4); XSLFSlideLayout layout5 = slide5.getSlideLayout(); XSLFTextShape shTitle = slide5.getTextShapeByType(Placeholder.TITLE); assertEquals("Hyperlinks", shTitle.getText()); @@ -247,6 +254,7 @@ public class TestXSLFSimpleShape extends TestCase { } @SuppressWarnings({ "deprecation", "unused" }) + @Test public void testShadowEffects(){ XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java index ecfd70eac2..fdfb46ee9a 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlide.java @@ -16,88 +16,91 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.*; import java.awt.Color; - -import junit.framework.TestCase; +import java.util.List; import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; /** * @author Yegor Kozlov */ -public class TestXSLFSlide extends TestCase { +public class TestXSLFSlide { + + @Test public void testReadShapes(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); - XSLFSlide[] slides = ppt.getSlides(); - - XSLFSlide slide1 = slides[0]; - XSLFShape[] shapes1 = slide1.getShapes(); - assertEquals(7, shapes1.length); - assertEquals("TextBox 3", shapes1[0].getShapeName()); - assertTrue(shapes1[0] instanceof XSLFTextBox); - XSLFAutoShape sh0 = (XSLFAutoShape)shapes1[0]; + List slides = ppt.getSlides(); + + XSLFSlide slide1 = slides.get(0); + List shapes1 = slide1.getShapes(); + assertEquals(7, shapes1.size()); + assertEquals("TextBox 3", shapes1.get(0).getShapeName()); + assertTrue(shapes1.get(0) instanceof XSLFTextBox); + XSLFAutoShape sh0 = (XSLFAutoShape)shapes1.get(0); assertEquals("Learning PPTX", sh0.getText()); - assertEquals("Straight Connector 5", shapes1[1].getShapeName()); - assertTrue(shapes1[1] instanceof XSLFConnectorShape); + assertEquals("Straight Connector 5", shapes1.get(1).getShapeName()); + assertTrue(shapes1.get(1) instanceof XSLFConnectorShape); - assertEquals("Freeform 6", shapes1[2].getShapeName()); - assertTrue(shapes1[2] instanceof XSLFFreeformShape); - XSLFAutoShape sh2 = (XSLFAutoShape)shapes1[2]; + assertEquals("Freeform 6", shapes1.get(2).getShapeName()); + assertTrue(shapes1.get(2) instanceof XSLFFreeformShape); + XSLFAutoShape sh2 = (XSLFAutoShape)shapes1.get(2); assertEquals("Cloud", sh2.getText()); - assertEquals("Picture 1", shapes1[3].getShapeName()); - assertTrue(shapes1[3] instanceof XSLFPictureShape); + assertEquals("Picture 1", shapes1.get(3).getShapeName()); + assertTrue(shapes1.get(3) instanceof XSLFPictureShape); - assertEquals("Table 2", shapes1[4].getShapeName()); - assertTrue(shapes1[4] instanceof XSLFGraphicFrame); + assertEquals("Table 2", shapes1.get(4).getShapeName()); + assertTrue(shapes1.get(4) instanceof XSLFGraphicFrame); - assertEquals("Straight Arrow Connector 7", shapes1[5].getShapeName()); - assertTrue(shapes1[5] instanceof XSLFConnectorShape); + assertEquals("Straight Arrow Connector 7", shapes1.get(5).getShapeName()); + assertTrue(shapes1.get(5) instanceof XSLFConnectorShape); - assertEquals("Elbow Connector 9", shapes1[6].getShapeName()); - assertTrue(shapes1[6] instanceof XSLFConnectorShape); + assertEquals("Elbow Connector 9", shapes1.get(6).getShapeName()); + assertTrue(shapes1.get(6) instanceof XSLFConnectorShape); // titles on slide2 - XSLFSlide slide2 = slides[1]; - XSLFShape[] shapes2 = slide2.getShapes(); - assertEquals(2, shapes2.length); - assertTrue(shapes2[0] instanceof XSLFAutoShape); - assertEquals("PPTX Title", ((XSLFAutoShape)shapes2[0]).getText()); - assertTrue(shapes2[1] instanceof XSLFAutoShape); - assertEquals("Subtitle\nAnd second line", ((XSLFAutoShape)shapes2[1]).getText()); + XSLFSlide slide2 = slides.get(1); + List shapes2 = slide2.getShapes(); + assertEquals(2, shapes2.size()); + assertTrue(shapes2.get(0) instanceof XSLFAutoShape); + assertEquals("PPTX Title", ((XSLFAutoShape)shapes2.get(0)).getText()); + assertTrue(shapes2.get(1) instanceof XSLFAutoShape); + assertEquals("Subtitle\nAnd second line", ((XSLFAutoShape)shapes2.get(1)).getText()); // group shape on slide3 - XSLFSlide slide3 = slides[2]; - XSLFShape[] shapes3 = slide3.getShapes(); - assertEquals(1, shapes3.length); - assertTrue(shapes3[0] instanceof XSLFGroupShape); - XSLFShape[] groupShapes = ((XSLFGroupShape)shapes3[0]).getShapes(); - assertEquals(3, groupShapes.length); - assertTrue(groupShapes[0] instanceof XSLFAutoShape); - assertEquals("Rectangle 1", groupShapes[0].getShapeName()); - - assertTrue(groupShapes[1] instanceof XSLFAutoShape); - assertEquals("Oval 2", groupShapes[1].getShapeName()); - - assertTrue(groupShapes[2] instanceof XSLFAutoShape); - assertEquals("Right Arrow 3", groupShapes[2].getShapeName()); - - XSLFSlide slide4 = slides[3]; - XSLFShape[] shapes4 = slide4.getShapes(); - assertEquals(1, shapes4.length); - assertTrue(shapes4[0] instanceof XSLFTable); - XSLFTable tbl = (XSLFTable)shapes4[0]; + XSLFSlide slide3 = slides.get(2); + List shapes3 = slide3.getShapes(); + assertEquals(1, shapes3.size()); + assertTrue(shapes3.get(0) instanceof XSLFGroupShape); + List groupShapes = ((XSLFGroupShape)shapes3.get(0)).getShapes(); + assertEquals(3, groupShapes.size()); + assertTrue(groupShapes.get(0) instanceof XSLFAutoShape); + assertEquals("Rectangle 1", groupShapes.get(0).getShapeName()); + + assertTrue(groupShapes.get(1) instanceof XSLFAutoShape); + assertEquals("Oval 2", groupShapes.get(1).getShapeName()); + + assertTrue(groupShapes.get(2) instanceof XSLFAutoShape); + assertEquals("Right Arrow 3", groupShapes.get(2).getShapeName()); + + XSLFSlide slide4 = slides.get(3); + List shapes4 = slide4.getShapes(); + assertEquals(1, shapes4.size()); + assertTrue(shapes4.get(0) instanceof XSLFTable); + XSLFTable tbl = (XSLFTable)shapes4.get(0); assertEquals(3, tbl.getNumberOfColumns()); assertEquals(6, tbl.getNumberOfRows()); } + @Test public void testCreateSlide(){ XMLSlideShow ppt = new XMLSlideShow(); - assertEquals(0, ppt.getSlides().length); + assertEquals(0, ppt.getSlides().size()); XSLFSlide slide = ppt.createSlide(); assertTrue(slide.getFollowMasterGraphics()); @@ -107,34 +110,35 @@ public class TestXSLFSlide extends TestCase { assertTrue(slide.getFollowMasterGraphics()); } + @Test public void testImportContent(){ XMLSlideShow ppt = new XMLSlideShow(); XMLSlideShow src = XSLFTestDataSamples.openSampleDocument("themes.pptx"); // create a blank slide and import content from the 4th slide of themes.pptx - XSLFSlide slide1 = ppt.createSlide().importContent(src.getSlides()[3]); - XSLFShape[] shapes1 = slide1.getShapes(); - assertEquals(2, shapes1.length); + XSLFSlide slide1 = ppt.createSlide().importContent(src.getSlides().get(3)); + List shapes1 = slide1.getShapes(); + assertEquals(2, shapes1.size()); - XSLFTextShape sh1 = (XSLFTextShape)shapes1[0]; + XSLFTextShape sh1 = (XSLFTextShape)shapes1.get(0); assertEquals("Austin Theme", sh1.getText()); XSLFTextRun r1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Century Gothic", r1.getFontFamily()); - assertEquals(40.0, r1.getFontSize()); + assertEquals(40.0, r1.getFontSize(), 0); assertTrue(r1.isBold()); assertTrue(r1.isItalic()); assertEquals(new Color(148, 198, 0), r1.getFontColor()); assertNull(sh1.getFillColor()); assertNull(sh1.getLineColor()); - XSLFTextShape sh2 = (XSLFTextShape)shapes1[1]; + XSLFTextShape sh2 = (XSLFTextShape)shapes1.get(1); assertEquals( "Text in a autoshape is white\n" + "Fill: RGB(148, 198,0)", sh2.getText()); XSLFTextRun r2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Century Gothic", r2.getFontFamily()); - assertEquals(18.0, r2.getFontSize()); + assertEquals(18.0, r2.getFontSize(), 0); assertFalse(r2.isBold()); assertFalse(r2.isItalic()); assertEquals(Color.white, r2.getFontColor()); @@ -142,11 +146,11 @@ public class TestXSLFSlide extends TestCase { assertEquals(new Color(74, 99, 0), sh2.getLineColor()); // slightly different from PowerPoint! // the 5th slide has a picture and a texture fill - XSLFSlide slide2 = ppt.createSlide().importContent(src.getSlides()[4]); - XSLFShape[] shapes2 = slide2.getShapes(); - assertEquals(2, shapes2.length); + XSLFSlide slide2 = ppt.createSlide().importContent(src.getSlides().get(4)); + List shapes2 = slide2.getShapes(); + assertEquals(2, shapes2.size()); - XSLFTextShape sh3 = (XSLFTextShape)shapes2[0]; + XSLFTextShape sh3 = (XSLFTextShape)shapes2.get(0); assertEquals("This slide overrides master background with a texture fill", sh3.getText()); XSLFTextRun r3 = sh3.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Century Gothic", r3.getFontFamily()); @@ -157,11 +161,12 @@ public class TestXSLFSlide extends TestCase { assertNull(sh3.getFillColor()); assertNull(sh3.getLineColor()); - XSLFPictureShape sh4 = (XSLFPictureShape)shapes2[1]; - XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides()[4].getShapes()[1]; + XSLFPictureShape sh4 = (XSLFPictureShape)shapes2.get(1); + XSLFPictureShape srcPic = (XSLFPictureShape)src.getSlides().get(4).getShapes().get(1); assertArrayEquals(sh4.getPictureData().getData(), srcPic.getPictureData().getData()); } + @Test public void testMergeSlides(){ XMLSlideShow ppt = new XMLSlideShow(); String[] pptx = {"shapes.pptx", "themes.pptx", "layouts.pptx", "backgrounds.pptx"}; @@ -173,6 +178,6 @@ public class TestXSLFSlide extends TestCase { ppt.createSlide().importContent(srcSlide); } } - assertEquals(30, ppt.getSlides().length); + assertEquals(30, ppt.getSlides().size()); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java index c3057d590f..3d20be87ea 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFSlideShow.java @@ -16,63 +16,68 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; -import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.xslf.XSLFTestDataSamples; +import static org.junit.Assert.*; import java.awt.Dimension; import java.util.List; +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; + /** * @author Yegor Kozlov */ -public class TestXSLFSlideShow extends TestCase { +public class TestXSLFSlideShow { + @Test public void testCreateSlide(){ XMLSlideShow ppt = new XMLSlideShow(); - assertEquals(0, ppt.getSlides().length); + assertEquals(0, ppt.getSlides().size()); XSLFSlide slide1 = ppt.createSlide(); - assertEquals(1, ppt.getSlides().length); - assertSame(slide1, ppt.getSlides()[0]); + assertEquals(1, ppt.getSlides().size()); + assertSame(slide1, ppt.getSlides().get(0)); List rels = slide1.getRelations(); assertEquals(1, rels.size()); assertEquals(slide1.getSlideMaster().getLayout(SlideLayout.BLANK), rels.get(0)); XSLFSlide slide2 = ppt.createSlide(); - assertEquals(2, ppt.getSlides().length); - assertSame(slide2, ppt.getSlides()[1]); + assertEquals(2, ppt.getSlides().size()); + assertSame(slide2, ppt.getSlides().get(1)); ppt.setSlideOrder(slide2, 0); - assertSame(slide2, ppt.getSlides()[0]); - assertSame(slide1, ppt.getSlides()[1]); + assertSame(slide2, ppt.getSlides().get(0)); + assertSame(slide1, ppt.getSlides().get(1)); ppt = XSLFTestDataSamples.writeOutAndReadBack(ppt); - assertEquals(2, ppt.getSlides().length); - rels = ppt.getSlides()[0].getRelations(); + assertEquals(2, ppt.getSlides().size()); + rels = ppt.getSlides().get(0).getRelations(); } + @Test public void testRemoveSlide(){ XMLSlideShow ppt = new XMLSlideShow(); - assertEquals(0, ppt.getSlides().length); + assertEquals(0, ppt.getSlides().size()); XSLFSlide slide1 = ppt.createSlide(); XSLFSlide slide2 = ppt.createSlide(); - assertEquals(2, ppt.getSlides().length); - assertSame(slide1, ppt.getSlides()[0]); - assertSame(slide2, ppt.getSlides()[1]); + assertEquals(2, ppt.getSlides().size()); + assertSame(slide1, ppt.getSlides().get(0)); + assertSame(slide2, ppt.getSlides().get(1)); XSLFSlide removedSlide = ppt.removeSlide(0); assertSame(slide1, removedSlide); - assertEquals(1, ppt.getSlides().length); - assertSame(slide2, ppt.getSlides()[0]); + assertEquals(1, ppt.getSlides().size()); + assertSame(slide2, ppt.getSlides().get(0)); ppt = XSLFTestDataSamples.writeOutAndReadBack(ppt); - assertEquals(1, ppt.getSlides().length); + assertEquals(1, ppt.getSlides().size()); } + @Test public void testDimension(){ XMLSlideShow ppt = new XMLSlideShow(); Dimension sz = ppt.getPageSize(); @@ -84,24 +89,26 @@ public class TestXSLFSlideShow extends TestCase { assertEquals(612, sz.height); } + @Test public void testSlideMasters(){ XMLSlideShow ppt = new XMLSlideShow(); - XSLFSlideMaster[] masters = ppt.getSlideMasters(); - assertEquals(1, masters.length); + List masters = ppt.getSlideMasters(); + assertEquals(1, masters.size()); XSLFSlide slide = ppt.createSlide(); - assertSame(masters[0], slide.getSlideMaster()); + assertSame(masters.get(0), slide.getSlideMaster()); } + @Test public void testSlideLayout(){ XMLSlideShow ppt = new XMLSlideShow(); - XSLFSlideMaster[] masters = ppt.getSlideMasters(); - assertEquals(1, masters.length); + List masters = ppt.getSlideMasters(); + assertEquals(1, masters.size()); XSLFSlide slide = ppt.createSlide(); XSLFSlideLayout layout = slide.getSlideLayout(); assertNotNull(layout); - assertSame(masters[0], layout.getSlideMaster()); + assertSame(masters.get(0), layout.getSlideMaster()); } } diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java index 80a52fd2cc..3b7c5cbcc2 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTable.java @@ -16,10 +16,11 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.*; import org.apache.poi.sl.usermodel.VerticalAlignment; import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableCell; import org.openxmlformats.schemas.presentationml.x2006.main.CTGraphicalObjectFrame; @@ -29,16 +30,16 @@ import java.util.List; /** * @author Yegor Kozlov */ -public class TestXSLFTable extends TestCase { - +public class TestXSLFTable { + @Test public void testRead(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("shapes.pptx"); - XSLFSlide slide = ppt.getSlides()[3]; - XSLFShape[] shapes = slide.getShapes(); - assertEquals(1, shapes.length); - assertTrue(shapes[0] instanceof XSLFTable); - XSLFTable tbl = (XSLFTable)shapes[0]; + XSLFSlide slide = ppt.getSlides().get(3); + List shapes = slide.getShapes(); + assertEquals(1, shapes.size()); + assertTrue(shapes.get(0) instanceof XSLFTable); + XSLFTable tbl = (XSLFTable)shapes.get(0); assertEquals(3, tbl.getNumberOfColumns()); assertEquals(6, tbl.getNumberOfRows()); assertNotNull(tbl.getCTTable()); @@ -46,13 +47,13 @@ public class TestXSLFTable extends TestCase { List rows = tbl.getRows(); assertEquals(6, rows.size()); - assertEquals(90.0, tbl.getColumnWidth(0)); - assertEquals(240.0, tbl.getColumnWidth(1)); - assertEquals(150.0, tbl.getColumnWidth(2)); + assertEquals(90.0, tbl.getColumnWidth(0), 0); + assertEquals(240.0, tbl.getColumnWidth(1), 0); + assertEquals(150.0, tbl.getColumnWidth(2), 0); for(XSLFTableRow row : tbl){ // all rows have the same height - assertEquals(29.2, row.getHeight()); + assertEquals(29.2, row.getHeight(), 0); } XSLFTableRow row0 = rows.get(0); @@ -70,6 +71,7 @@ public class TestXSLFTable extends TestCase { assertEquals("C1", cells1.get(2).getText()); } + @Test public void testCreate() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -92,9 +94,9 @@ public class TestXSLFTable extends TestCase { assertNotNull(row0.getXmlObject()); assertEquals(1, tbl.getNumberOfRows()); assertSame(row0, tbl.getRows().get(0)); - assertEquals(20.0, row0.getHeight()); + assertEquals(20.0, row0.getHeight(), 0); row0.setHeight(30.0); - assertEquals(30.0, row0.getHeight()); + assertEquals(30.0, row0.getHeight(), 0); assertEquals(0, row0.getCells().size()); XSLFTableCell cell0 = row0.addCell(); @@ -108,41 +110,41 @@ public class TestXSLFTable extends TestCase { assertSame(cell0, row0.getCells().get(0)); assertEquals(1, tbl.getNumberOfColumns()); - assertEquals(100.0, tbl.getColumnWidth(0)); + assertEquals(100.0, tbl.getColumnWidth(0), 0); cell0.addNewTextParagraph().addNewTextRun().setText("POI"); assertEquals("POI", cell0.getText()); XSLFTableCell cell1 = row0.addCell(); assertSame(cell1, row0.getCells().get(1)); assertEquals(2, tbl.getNumberOfColumns()); - assertEquals(100.0, tbl.getColumnWidth(1)); + assertEquals(100.0, tbl.getColumnWidth(1), 0); cell1.addNewTextParagraph().addNewTextRun().setText("Apache"); assertEquals("Apache", cell1.getText()); - assertEquals(1.0, cell1.getBorderBottom()); + assertEquals(1.0, cell1.getBorderBottom(), 0); cell1.setBorderBottom(2.0); - assertEquals(2.0, cell1.getBorderBottom()); + assertEquals(2.0, cell1.getBorderBottom(), 0); assertNull(cell1.getBorderBottomColor()); cell1.setBorderBottomColor(Color.yellow); assertEquals(Color.yellow, cell1.getBorderBottomColor()); - assertEquals(1.0, cell1.getBorderTop()); + assertEquals(1.0, cell1.getBorderTop(), 0); cell1.setBorderTop(2.0); - assertEquals(2.0, cell1.getBorderTop()); + assertEquals(2.0, cell1.getBorderTop(), 0); assertNull(cell1.getBorderTopColor()); cell1.setBorderTopColor(Color.yellow); assertEquals(Color.yellow, cell1.getBorderTopColor()); - assertEquals(1.0, cell1.getBorderLeft()); + assertEquals(1.0, cell1.getBorderLeft(), 0); cell1.setBorderLeft(2.0); - assertEquals(2.0, cell1.getBorderLeft()); + assertEquals(2.0, cell1.getBorderLeft(), 0); assertNull(cell1.getBorderLeftColor()); cell1.setBorderLeftColor(Color.yellow); assertEquals(Color.yellow, cell1.getBorderLeftColor()); - assertEquals(1.0, cell1.getBorderRight()); + assertEquals(1.0, cell1.getBorderRight(), 0); cell1.setBorderRight(2.0); - assertEquals(2.0, cell1.getBorderRight()); + assertEquals(2.0, cell1.getBorderRight(), 0); assertNull(cell1.getBorderRightColor()); cell1.setBorderRightColor(Color.yellow); assertEquals(Color.yellow, cell1.getBorderRightColor()); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java index 3ce6c3b6d2..49b5fd4944 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTableStyles.java @@ -16,14 +16,18 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTTableStyle; /** * @author Yegor Kozlov */ -public class TestXSLFTableStyles extends TestCase { +public class TestXSLFTableStyles { + @Test public void testRead(){ XMLSlideShow ppt = new XMLSlideShow(); XSLFTableStyles tblStyles = ppt.getTableStyles(); @@ -32,6 +36,8 @@ public class TestXSLFTableStyles extends TestCase { assertEquals(0, tblStyles.getStyles().size()); } + @SuppressWarnings("unused") + @Test public void testStyle(){ CTTableStyle obj = CTTableStyle.Factory.newInstance(); XSLFTableStyle style = new XSLFTableStyle(obj); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java index 2176a1b2ea..40e07a6910 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextBox.java @@ -16,14 +16,18 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import org.junit.Test; import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties; /** * @author Yegor Kozlov */ -public class TestXSLFTextBox extends TestCase { +public class TestXSLFTextBox { + @Test public void testPlaceholder() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -40,6 +44,7 @@ public class TestXSLFTextBox extends TestCase { /** * text box inherits default text proeprties from presentation.xml */ + @Test public void testDefaultTextStyle() { XMLSlideShow ppt = new XMLSlideShow(); XSLFSlide slide = ppt.createSlide(); @@ -55,12 +60,12 @@ public class TestXSLFTextBox extends TestCase { XSLFTextRun r = shape.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(1800, pPr.getSz()); - assertEquals(18.0, r.getFontSize()); + assertEquals(18.0, r.getFontSize(), 0); assertEquals("Calibri", r.getFontFamily()); pPr.setSz(900); pPr.getLatin().setTypeface("Arial"); - assertEquals(9.0, r.getFontSize()); + assertEquals(9.0, r.getFontSize(), 0); assertEquals("Arial", r.getFontFamily()); // unset font size in presentation.xml. The value should be taken from master slide @@ -68,12 +73,12 @@ public class TestXSLFTextBox extends TestCase { ppt.getCTPresentation().getDefaultTextStyle().getLvl1PPr().getDefRPr().unsetSz(); pPr = slide.getSlideMaster().getXmlObject().getTxStyles().getOtherStyle().getLvl1PPr().getDefRPr(); assertEquals(1800, pPr.getSz()); - assertEquals(18.0, r.getFontSize()); + assertEquals(18.0, r.getFontSize(), 0); pPr.setSz(2000); - assertEquals(20.0, r.getFontSize()); + assertEquals(20.0, r.getFontSize(), 0); pPr.unsetSz(); // Should never be - assertEquals(-1.0, r.getFontSize()); + assertEquals(-1.0, r.getFontSize(), 0); } } \ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java index fb906ed3a1..0998ee8e72 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextParagraph.java @@ -242,14 +242,14 @@ public class TestXSLFTextParagraph { @Test public void testThemeInheritance(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("prProps.pptx"); - XSLFShape[] shapes = ppt.getSlides()[0].getShapes(); - XSLFTextShape sh1 = (XSLFTextShape)shapes[0]; + List shapes = ppt.getSlides().get(0).getShapes(); + XSLFTextShape sh1 = (XSLFTextShape)shapes.get(0); assertEquals("Apache", sh1.getText()); assertEquals(TextAlign.CENTER, sh1.getTextParagraphs().get(0).getTextAlign()); - XSLFTextShape sh2 = (XSLFTextShape)shapes[1]; + XSLFTextShape sh2 = (XSLFTextShape)shapes.get(1); assertEquals("Software", sh2.getText()); assertEquals(TextAlign.CENTER, sh2.getTextParagraphs().get(0).getTextAlign()); - XSLFTextShape sh3 = (XSLFTextShape)shapes[2]; + XSLFTextShape sh3 = (XSLFTextShape)shapes.get(2); assertEquals("Foundation", sh3.getText()); assertEquals(TextAlign.CENTER, sh3.getTextParagraphs().get(0).getTextAlign()); } @@ -350,7 +350,7 @@ public class TestXSLFTextParagraph { XSLFTextRun r1 = p.addNewTextRun(); r1.setText("Hello,"); XSLFTextRun r2 = p.addLineBreak(); - assertEquals("\n", r2.getText()); + assertEquals("\n", r2.getRawText()); r2.setFontSize(10.0); assertEquals(10.0, r2.getFontSize(), 0); XSLFTextRun r3 = p.addNewTextRun(); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java index f9232a1733..b19d069b0d 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTextShape.java @@ -16,9 +16,10 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import java.awt.Color; +import static org.junit.Assert.*; -import junit.framework.TestCase; +import java.awt.Color; +import java.util.List; import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; import org.apache.poi.sl.usermodel.VerticalAlignment; @@ -30,28 +31,28 @@ import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType; /** * @author Yegor Kozlov */ -public class TestXSLFTextShape extends TestCase { +public class TestXSLFTextShape { public void testLayouts(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("layouts.pptx"); - XSLFSlide[] slide = ppt.getSlides(); + List slide = ppt.getSlides(); - verifySlide1(slide[0]); - verifySlide2(slide[1]); - verifySlide3(slide[2]); - verifySlide4(slide[3]); - verifySlide7(slide[6]); - verifySlide8(slide[7]); - verifySlide10(slide[9]); + verifySlide1(slide.get(0)); + verifySlide2(slide.get(1)); + verifySlide3(slide.get(2)); + verifySlide4(slide.get(3)); + verifySlide7(slide.get(6)); + verifySlide8(slide.get(7)); + verifySlide10(slide.get(9)); } void verifySlide1(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Title Slide",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.CTR_TITLE, ph1.getType()); // anchor is not defined in the shape @@ -68,20 +69,20 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties assertEquals("Centered Title", shape1.getText()); XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(44.0, r1.getFontSize()); + assertEquals(44.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTPlaceholder ph2 = shape2.getCTPlaceholder(); assertEquals(STPlaceholderType.SUB_TITLE, ph2.getType()); // anchor is not defined in the shape @@ -98,26 +99,26 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); assertEquals("subtitle", shape2.getText()); XSLFTextRun r2 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Calibri", r2.getFontFamily()); - assertEquals(32.0, r2.getFontSize()); + assertEquals(32.0, r2.getFontSize(), 0); // TODO fix calculation of tint //assertEquals(new Color(137, 137, 137), r2.getFontColor()); } void verifySlide2(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Title and Content",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.TITLE, ph1.getType()); // anchor is not defined in the shape @@ -137,20 +138,20 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties assertEquals("Title", shape1.getText()); XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(44.0, r1.getFontSize()); + assertEquals(44.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTPlaceholder ph2 = shape2.getCTPlaceholder(); assertFalse(ph2.isSetType()); // assertTrue(ph2.isSetIdx()); @@ -172,54 +173,54 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr1.getParentParagraph().getLevel()); - assertEquals("Content", pr1.getText()); + assertEquals("Content", pr1.getRawText()); assertEquals("Calibri", pr1.getFontFamily()); - assertEquals(32.0, pr1.getFontSize()); - assertEquals(27.0, pr1.getParentParagraph().getLeftMargin()); + assertEquals(32.0, pr1.getFontSize(), 0); + assertEquals(27.0, pr1.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr1.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr1.getParentParagraph().getBulletFont()); XSLFTextRun pr2 = shape2.getTextParagraphs().get(1).getTextRuns().get(0); assertEquals(1, pr2.getParentParagraph().getLevel()); - assertEquals("Level 2", pr2.getText()); + assertEquals("Level 2", pr2.getRawText()); assertEquals("Calibri", pr2.getFontFamily()); - assertEquals(28.0, pr2.getFontSize()); - assertEquals(58.5, pr2.getParentParagraph().getLeftMargin()); + assertEquals(28.0, pr2.getFontSize(), 0); + assertEquals(58.5, pr2.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr2.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr2.getParentParagraph().getBulletFont()); XSLFTextRun pr3 = shape2.getTextParagraphs().get(2).getTextRuns().get(0); assertEquals(2, pr3.getParentParagraph().getLevel()); - assertEquals("Level 3", pr3.getText()); + assertEquals("Level 3", pr3.getRawText()); assertEquals("Calibri", pr3.getFontFamily()); - assertEquals(24.0, pr3.getFontSize()); - assertEquals(90.0, pr3.getParentParagraph().getLeftMargin()); + assertEquals(24.0, pr3.getFontSize(), 0); + assertEquals(90.0, pr3.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr3.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr3.getParentParagraph().getBulletFont()); XSLFTextRun pr4 = shape2.getTextParagraphs().get(3).getTextRuns().get(0); assertEquals(3, pr4.getParentParagraph().getLevel()); - assertEquals("Level 4", pr4.getText()); + assertEquals("Level 4", pr4.getRawText()); assertEquals("Calibri", pr4.getFontFamily()); - assertEquals(20.0, pr4.getFontSize()); - assertEquals(126.0, pr4.getParentParagraph().getLeftMargin()); + assertEquals(20.0, pr4.getFontSize(), 0); + assertEquals(126.0, pr4.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr4.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr4.getParentParagraph().getBulletFont()); XSLFTextRun pr5 = shape2.getTextParagraphs().get(4).getTextRuns().get(0); assertEquals(4, pr5.getParentParagraph().getLevel()); - assertEquals("Level 5", pr5.getText()); + assertEquals("Level 5", pr5.getRawText()); assertEquals("Calibri", pr5.getFontFamily()); - assertEquals(20.0, pr5.getFontSize()); - assertEquals(162.0, pr5.getParentParagraph().getLeftMargin()); + assertEquals(20.0, pr5.getFontSize(), 0); + assertEquals(162.0, pr5.getParentParagraph().getLeftMargin(), 0); assertEquals("\u00bb", pr5.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr5.getParentParagraph().getBulletFont()); @@ -227,10 +228,10 @@ public class TestXSLFTextShape extends TestCase { void verifySlide3(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Section Header",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.TITLE, ph1.getType()); // anchor is not defined in the shape @@ -247,10 +248,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape1.getVerticalAlignment()); // now check text properties @@ -258,13 +259,13 @@ public class TestXSLFTextShape extends TestCase { XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign()); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(40.0, r1.getFontSize()); + assertEquals(40.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); assertTrue(r1.isBold()); assertFalse(r1.isItalic()); - assertFalse(r1.isUnderline()); + assertFalse(r1.isUnderlined()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTPlaceholder ph2 = shape2.getCTPlaceholder(); assertEquals(STPlaceholderType.BODY, ph2.getType()); // anchor is not defined in the shape @@ -281,27 +282,27 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.BOTTOM, shape2.getVerticalAlignment()); assertEquals("Section Header", shape2.getText()); XSLFTextRun r2 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.LEFT, r2.getParentParagraph().getTextAlign()); assertEquals("Calibri", r2.getFontFamily()); - assertEquals(20.0, r2.getFontSize()); + assertEquals(20.0, r2.getFontSize(), 0); // TODO fix calculation of tint //assertEquals(new Color(137, 137, 137), r2.getFontColor()); } void verifySlide4(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Two Content",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.TITLE, ph1.getType()); // anchor is not defined in the shape @@ -321,10 +322,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -332,10 +333,10 @@ public class TestXSLFTextShape extends TestCase { XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign()); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(44.0, r1.getFontSize()); + assertEquals(44.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTPlaceholder ph2 = shape2.getCTPlaceholder(); assertFalse(ph2.isSetType()); assertTrue(ph2.isSetIdx()); @@ -354,18 +355,18 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr1.getParentParagraph().getLevel()); - assertEquals("Left", pr1.getText()); + assertEquals("Left", pr1.getRawText()); assertEquals("Calibri", pr1.getFontFamily()); - assertEquals(28.0, pr1.getFontSize()); - assertEquals(27.0, pr1.getParentParagraph().getLeftMargin()); + assertEquals(28.0, pr1.getFontSize(), 0); + assertEquals(27.0, pr1.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr1.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr1.getParentParagraph().getBulletFont()); @@ -373,8 +374,8 @@ public class TestXSLFTextShape extends TestCase { assertEquals(1, pr2.getParentParagraph().getLevel()); assertEquals("Level 2", pr2.getParentParagraph().getText()); assertEquals("Calibri", pr2.getFontFamily()); - assertEquals(24.0, pr2.getFontSize()); - assertEquals(58.5, pr2.getParentParagraph().getLeftMargin()); + assertEquals(24.0, pr2.getFontSize(), 0); + assertEquals(58.5, pr2.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr2.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr2.getParentParagraph().getBulletFont()); @@ -382,8 +383,8 @@ public class TestXSLFTextShape extends TestCase { assertEquals(2, pr3.getParentParagraph().getLevel()); assertEquals("Level 3", pr3.getParentParagraph().getText()); assertEquals("Calibri", pr3.getFontFamily()); - assertEquals(20.0, pr3.getFontSize()); - assertEquals(90.0, pr3.getParentParagraph().getLeftMargin()); + assertEquals(20.0, pr3.getFontSize(), 0); + assertEquals(90.0, pr3.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr3.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr3.getParentParagraph().getBulletFont()); @@ -391,31 +392,32 @@ public class TestXSLFTextShape extends TestCase { assertEquals(3, pr4.getParentParagraph().getLevel()); assertEquals("Level 4", pr4.getParentParagraph().getText()); assertEquals("Calibri", pr4.getFontFamily()); - assertEquals(18.0, pr4.getFontSize()); - assertEquals(126.0, pr4.getParentParagraph().getLeftMargin()); + assertEquals(18.0, pr4.getFontSize(), 0); + assertEquals(126.0, pr4.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr4.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr4.getParentParagraph().getBulletFont()); - XSLFTextShape shape3 = (XSLFTextShape)shapes[2]; + XSLFTextShape shape3 = (XSLFTextShape)shapes.get(2); XSLFTextRun pr5 = shape3.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr5.getParentParagraph().getLevel()); - assertEquals("Right", pr5.getText()); + assertEquals("Right", pr5.getRawText()); assertEquals("Calibri", pr5.getFontFamily()); assertEquals(Color.black, pr5.getFontColor()); } + @SuppressWarnings("unused") void verifySlide5(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); // TODO } void verifySlide7(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Blank",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.TITLE, ph1.getType()); // anchor is not defined in the shape @@ -428,10 +430,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.MIDDLE, shape1.getVerticalAlignment()); // now check text properties @@ -439,11 +441,11 @@ public class TestXSLFTextShape extends TestCase { XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign()); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(44.0, r1.getFontSize()); + assertEquals(44.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); assertFalse(r1.isBold()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTTextBodyProperties bodyPr2 = shape2.getTextBodyPr(); // none of the following properties are set in the shapes and fetched from the master shape @@ -452,19 +454,19 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr1.getParentParagraph().getLevel()); - assertEquals("Default Text", pr1.getText()); + assertEquals("Default Text", pr1.getRawText()); assertEquals("Calibri", pr1.getFontFamily()); - assertEquals(18.0, pr1.getFontSize()); + assertEquals(18.0, pr1.getFontSize(), 0); - XSLFTextShape shape3 = (XSLFTextShape)shapes[2]; + XSLFTextShape shape3 = (XSLFTextShape)shapes.get(2); assertEquals("Default", shape3.getTextParagraphs().get(0).getText()); assertEquals("Text with levels", shape3.getTextParagraphs().get(1).getText()); assertEquals("Level 1", shape3.getTextParagraphs().get(2).getText()); @@ -474,16 +476,16 @@ public class TestXSLFTextShape extends TestCase { for(int p = 0; p < 5; p++) { XSLFTextParagraph pr = shape3.getTextParagraphs().get(p); assertEquals("Calibri", pr.getTextRuns().get(0).getFontFamily()); - assertEquals(18.0, pr.getTextRuns().get(0).getFontSize()); + assertEquals(18.0, pr.getTextRuns().get(0).getFontSize(), 0); } } void verifySlide8(XSLFSlide slide){ XSLFSlideLayout layout = slide.getSlideLayout(); - XSLFShape[] shapes = slide.getShapes(); + List shapes = slide.getShapes(); assertEquals("Content with Caption",layout.getName()); - XSLFTextShape shape1 = (XSLFTextShape)shapes[0]; + XSLFTextShape shape1 = (XSLFTextShape)shapes.get(0); CTPlaceholder ph1 = shape1.getCTPlaceholder(); assertEquals(STPlaceholderType.TITLE, ph1.getType()); // anchor is not defined in the shape @@ -501,10 +503,10 @@ public class TestXSLFTextShape extends TestCase { !bodyPr1.isSetBIns() && !bodyPr1.isSetTIns() && !bodyPr1.isSetAnchor() ); - assertEquals(7.2, shape1.getLeftInset()); // 0.1" - assertEquals(7.2, shape1.getRightInset()); // 0.1" - assertEquals(3.6, shape1.getTopInset()); // 0.05" - assertEquals(3.6, shape1.getBottomInset()); // 0.05" + assertEquals(7.2, shape1.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape1.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape1.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape1.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.BOTTOM, shape1.getVerticalAlignment()); // now check text properties @@ -512,11 +514,11 @@ public class TestXSLFTextShape extends TestCase { XSLFTextRun r1 = shape1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.LEFT, r1.getParentParagraph().getTextAlign()); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(20.0, r1.getFontSize()); + assertEquals(20.0, r1.getFontSize(), 0); assertEquals(Color.black, r1.getFontColor()); assertTrue(r1.isBold()); - XSLFTextShape shape2 = (XSLFTextShape)shapes[1]; + XSLFTextShape shape2 = (XSLFTextShape)shapes.get(1); CTPlaceholder ph2 = shape2.getCTPlaceholder(); assertFalse(ph2.isSetType()); assertTrue(ph2.isSetIdx()); @@ -535,18 +537,18 @@ public class TestXSLFTextShape extends TestCase { !bodyPr2.isSetBIns() && !bodyPr2.isSetTIns() && !bodyPr2.isSetAnchor() ); - assertEquals(7.2, shape2.getLeftInset()); // 0.1" - assertEquals(7.2, shape2.getRightInset()); // 0.1" - assertEquals(3.6, shape2.getTopInset()); // 0.05" - assertEquals(3.6, shape2.getBottomInset()); // 0.05" + assertEquals(7.2, shape2.getLeftInset(), 0); // 0.1" + assertEquals(7.2, shape2.getRightInset(), 0); // 0.1" + assertEquals(3.6, shape2.getTopInset(), 0); // 0.05" + assertEquals(3.6, shape2.getBottomInset(), 0); // 0.05" assertEquals(VerticalAlignment.TOP, shape2.getVerticalAlignment()); XSLFTextRun pr1 = shape2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr1.getParentParagraph().getLevel()); - assertEquals("Level 1", pr1.getText()); + assertEquals("Level 1", pr1.getRawText()); assertEquals("Calibri", pr1.getFontFamily()); - assertEquals(32.0, pr1.getFontSize()); - assertEquals(27.0, pr1.getParentParagraph().getLeftMargin()); + assertEquals(32.0, pr1.getFontSize(), 0); + assertEquals(27.0, pr1.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr1.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr1.getParentParagraph().getBulletFont()); @@ -554,8 +556,8 @@ public class TestXSLFTextShape extends TestCase { assertEquals(1, pr2.getParentParagraph().getLevel()); assertEquals("Level 2", pr2.getParentParagraph().getText()); assertEquals("Calibri", pr2.getFontFamily()); - assertEquals(28.0, pr2.getFontSize()); - assertEquals(58.5, pr2.getParentParagraph().getLeftMargin()); + assertEquals(28.0, pr2.getFontSize(), 0); + assertEquals(58.5, pr2.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr2.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr2.getParentParagraph().getBulletFont()); @@ -563,8 +565,8 @@ public class TestXSLFTextShape extends TestCase { assertEquals(2, pr3.getParentParagraph().getLevel()); assertEquals("Level 3", pr3.getParentParagraph().getText()); assertEquals("Calibri", pr3.getFontFamily()); - assertEquals(24.0, pr3.getFontSize()); - assertEquals(90.0, pr3.getParentParagraph().getLeftMargin()); + assertEquals(24.0, pr3.getFontSize(), 0); + assertEquals(90.0, pr3.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2022", pr3.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr3.getParentParagraph().getBulletFont()); @@ -572,20 +574,20 @@ public class TestXSLFTextShape extends TestCase { assertEquals(3, pr4.getParentParagraph().getLevel()); assertEquals("Level 4", pr4.getParentParagraph().getText()); assertEquals("Calibri", pr4.getFontFamily()); - assertEquals(20.0, pr4.getFontSize()); - assertEquals(126.0, pr4.getParentParagraph().getLeftMargin()); + assertEquals(20.0, pr4.getFontSize(), 0); + assertEquals(126.0, pr4.getParentParagraph().getLeftMargin(), 0); assertEquals("\u2013", pr4.getParentParagraph().getBulletCharacter()); assertEquals("Arial", pr4.getParentParagraph().getBulletFont()); - XSLFTextShape shape3 = (XSLFTextShape)shapes[2]; + XSLFTextShape shape3 = (XSLFTextShape)shapes.get(2); assertEquals(VerticalAlignment.TOP, shape3.getVerticalAlignment()); assertEquals("Content with caption", shape3.getText()); pr1 = shape3.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(0, pr1.getParentParagraph().getLevel()); - assertEquals("Content with caption", pr1.getText()); + assertEquals("Content with caption", pr1.getRawText()); assertEquals("Calibri", pr1.getFontFamily()); - assertEquals(14.0, pr1.getFontSize()); + assertEquals(14.0, pr1.getFontSize(), 0); } @@ -599,7 +601,7 @@ public class TestXSLFTextShape extends TestCase { XSLFTextRun r1 = footer.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(TextAlign.CENTER, r1.getParentParagraph().getTextAlign()); assertEquals("Calibri", r1.getFontFamily()); - assertEquals(12.0, r1.getFontSize()); + assertEquals(12.0, r1.getFontSize(), 0); // TODO calculation of tint is incorrect assertEquals(new Color(64,64,64), r1.getFontColor()); @@ -614,14 +616,14 @@ public class TestXSLFTextShape extends TestCase { public void testTitleStyles(){ XMLSlideShow ppt = new XMLSlideShow(); - XSLFSlideMaster master = ppt.getSlideMasters()[0]; + XSLFSlideMaster master = ppt.getSlideMasters().get(0); XSLFTheme theme = master.getTheme(); XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE); XSLFSlide slide = ppt.createSlide(layout) ; assertSame(layout, slide.getSlideLayout()); assertSame(master, slide.getSlideMaster()); - XSLFTextShape titleShape = (XSLFTextShape)slide.getPlaceholder(0); + XSLFTextShape titleShape = slide.getPlaceholder(0); titleShape.setText("Apache POI"); XSLFTextParagraph paragraph = titleShape.getTextParagraphs().get(0); XSLFTextRun textRun = paragraph.getTextRuns().get(0); @@ -631,12 +633,12 @@ public class TestXSLFTextShape extends TestCase { CTTextParagraphProperties lv1PPr = master.getXmlObject().getTxStyles().getTitleStyle().getLvl1PPr(); CTTextCharacterProperties lv1CPr = lv1PPr.getDefRPr(); assertEquals(4400, lv1CPr.getSz()); - assertEquals(44.0, textRun.getFontSize()); + assertEquals(44.0, textRun.getFontSize(), 0); assertEquals("+mj-lt", lv1CPr.getLatin().getTypeface()); assertEquals("Calibri", theme.getMajorFont()); assertEquals("Calibri", textRun.getFontFamily()); lv1CPr.setSz(3200); - assertEquals(32.0, textRun.getFontSize()); + assertEquals(32.0, textRun.getFontSize(), 0); lv1CPr.getLatin().setTypeface("Arial"); assertEquals("Arial", textRun.getFontFamily()); assertEquals(STTextAlignType.CTR, lv1PPr.getAlgn()); @@ -650,7 +652,7 @@ public class TestXSLFTextShape extends TestCase { CTTextParagraphProperties lv2PPr = tx2.getTextBody(true).getLstStyle().addNewLvl1PPr(); CTTextCharacterProperties lv2CPr = lv2PPr.addNewDefRPr(); lv2CPr.setSz(3300); - assertEquals(33.0, textRun.getFontSize()); + assertEquals(33.0, textRun.getFontSize(), 0); lv2CPr.addNewLatin().setTypeface("Times"); assertEquals("Times", textRun.getFontFamily()); lv2PPr.setAlgn(STTextAlignType.R); @@ -663,7 +665,7 @@ public class TestXSLFTextShape extends TestCase { CTTextParagraphProperties lv3PPr = tx3.getTextBody(true).getLstStyle().addNewLvl1PPr(); CTTextCharacterProperties lv3CPr = lv3PPr.addNewDefRPr(); lv3CPr.setSz(3400); - assertEquals(34.0, textRun.getFontSize()); + assertEquals(34.0, textRun.getFontSize(), 0); lv3CPr.addNewLatin().setTypeface("Courier New"); assertEquals("Courier New", textRun.getFontFamily()); lv3PPr.setAlgn(STTextAlignType.CTR); @@ -674,7 +676,7 @@ public class TestXSLFTextShape extends TestCase { CTTextParagraphProperties lv4PPr = titleShape.getTextBody(true).getLstStyle().addNewLvl1PPr(); CTTextCharacterProperties lv4CPr = lv4PPr.addNewDefRPr(); lv4CPr.setSz(3500); - assertEquals(35.0, textRun.getFontSize()); + assertEquals(35.0, textRun.getFontSize(), 0); lv4CPr.addNewLatin().setTypeface("Arial"); assertEquals("Arial", textRun.getFontFamily()); lv4PPr.setAlgn(STTextAlignType.L); @@ -684,7 +686,7 @@ public class TestXSLFTextShape extends TestCase { CTTextParagraphProperties lv5PPr = paragraph.getXmlObject().addNewPPr(); CTTextCharacterProperties lv5CPr = textRun.getXmlObject().getRPr(); lv5CPr.setSz(3600); - assertEquals(36.0, textRun.getFontSize()); + assertEquals(36.0, textRun.getFontSize(), 0); lv5CPr.addNewLatin().setTypeface("Calibri"); assertEquals("Calibri", textRun.getFontFamily()); lv5PPr.setAlgn(STTextAlignType.CTR); @@ -694,14 +696,14 @@ public class TestXSLFTextShape extends TestCase { public void testBodyStyles(){ XMLSlideShow ppt = new XMLSlideShow(); - XSLFSlideMaster master = ppt.getSlideMasters()[0]; + XSLFSlideMaster master = ppt.getSlideMasters().get(0); XSLFTheme theme = master.getTheme(); XSLFSlideLayout layout = master.getLayout(SlideLayout.TITLE_AND_CONTENT); XSLFSlide slide = ppt.createSlide(layout) ; assertSame(layout, slide.getSlideLayout()); assertSame(master, slide.getSlideMaster()); - XSLFTextShape tx1 = (XSLFTextShape)slide.getPlaceholder(1); + XSLFTextShape tx1 = slide.getPlaceholder(1); tx1.clearText(); XSLFTextParagraph p1 = tx1.addNewTextParagraph(); @@ -731,12 +733,12 @@ public class TestXSLFTextShape extends TestCase { CTTextCharacterProperties lv3CPr = lv3PPr.getDefRPr(); // lv1 assertEquals(3200, lv1CPr.getSz()); - assertEquals(32.0, r1.getFontSize()); + assertEquals(32.0, r1.getFontSize(), 0); assertEquals("+mn-lt", lv1CPr.getLatin().getTypeface()); assertEquals("Calibri", theme.getMinorFont()); assertEquals("Calibri", r1.getFontFamily()); lv1CPr.setSz(3300); - assertEquals(33.0, r1.getFontSize()); + assertEquals(33.0, r1.getFontSize(), 0); lv1CPr.getLatin().setTypeface("Arial"); assertEquals("Arial", r1.getFontFamily()); assertEquals(STTextAlignType.L, lv1PPr.getAlgn()); @@ -745,9 +747,9 @@ public class TestXSLFTextShape extends TestCase { assertEquals(TextAlign.RIGHT, p1.getTextAlign()); //lv2 assertEquals(2800, lv2CPr.getSz()); - assertEquals(28.0, r2.getFontSize()); + assertEquals(28.0, r2.getFontSize(), 0); lv2CPr.setSz(3300); - assertEquals(33.0, r2.getFontSize()); + assertEquals(33.0, r2.getFontSize(), 0); lv2CPr.getLatin().setTypeface("Times"); assertEquals("Times", r2.getFontFamily()); assertEquals(STTextAlignType.L, lv2PPr.getAlgn()); @@ -756,9 +758,9 @@ public class TestXSLFTextShape extends TestCase { assertEquals(TextAlign.RIGHT, p2.getTextAlign()); //lv3 assertEquals(2400, lv3CPr.getSz()); - assertEquals(24.0, r3.getFontSize()); + assertEquals(24.0, r3.getFontSize(), 0); lv3CPr.setSz(2500); - assertEquals(25.0, r3.getFontSize()); + assertEquals(25.0, r3.getFontSize(), 0); lv3CPr.getLatin().setTypeface("Courier New"); assertEquals("Courier New", r3.getFontFamily()); assertEquals(STTextAlignType.L, lv3PPr.getAlgn()); @@ -780,21 +782,21 @@ public class TestXSLFTextShape extends TestCase { lv3CPr = lv3PPr.addNewDefRPr(); lv1CPr.setSz(3300); - assertEquals(33.0, r1.getFontSize()); + assertEquals(33.0, r1.getFontSize(), 0); lv1CPr.addNewLatin().setTypeface("Times"); assertEquals("Times", r1.getFontFamily()); lv1PPr.setAlgn(STTextAlignType.L); assertEquals(TextAlign.LEFT, p1.getTextAlign()); lv2CPr.setSz(3300); - assertEquals(33.0, r2.getFontSize()); + assertEquals(33.0, r2.getFontSize(), 0); lv2CPr.addNewLatin().setTypeface("Times"); assertEquals("Times", r2.getFontFamily()); lv2PPr.setAlgn(STTextAlignType.L); assertEquals(TextAlign.LEFT, p2.getTextAlign()); lv3CPr.setSz(3300); - assertEquals(33.0, r3.getFontSize()); + assertEquals(33.0, r3.getFontSize(), 0); lv3CPr.addNewLatin().setTypeface("Times"); assertEquals("Times", r3.getFontFamily()); lv3PPr.setAlgn(STTextAlignType.L); @@ -812,21 +814,21 @@ public class TestXSLFTextShape extends TestCase { lv3CPr = lv3PPr.addNewDefRPr(); lv1CPr.setSz(3400); - assertEquals(34.0, r1.getFontSize()); + assertEquals(34.0, r1.getFontSize(), 0); lv1CPr.addNewLatin().setTypeface("Courier New"); assertEquals("Courier New", r1.getFontFamily()); lv1PPr.setAlgn(STTextAlignType.CTR); assertEquals(TextAlign.CENTER, p1.getTextAlign()); lv2CPr.setSz(3400); - assertEquals(34.0, r2.getFontSize()); + assertEquals(34.0, r2.getFontSize(), 0); lv2CPr.addNewLatin().setTypeface("Courier New"); assertEquals("Courier New", r2.getFontFamily()); lv2PPr.setAlgn(STTextAlignType.CTR); assertEquals(TextAlign.CENTER, p2.getTextAlign()); lv3CPr.setSz(3400); - assertEquals(34.0, r3.getFontSize()); + assertEquals(34.0, r3.getFontSize(), 0); lv3CPr.addNewLatin().setTypeface("Courier New"); assertEquals("Courier New", r3.getFontFamily()); lv3PPr.setAlgn(STTextAlignType.CTR); @@ -842,21 +844,21 @@ public class TestXSLFTextShape extends TestCase { lv3CPr = lv3PPr.addNewDefRPr(); lv1CPr.setSz(3500); - assertEquals(35.0, r1.getFontSize()); + assertEquals(35.0, r1.getFontSize(), 0); lv1CPr.addNewLatin().setTypeface("Arial"); assertEquals("Arial", r1.getFontFamily()); lv1PPr.setAlgn(STTextAlignType.L); assertEquals(TextAlign.LEFT, p1.getTextAlign()); lv2CPr.setSz(3500); - assertEquals(35.0, r2.getFontSize()); + assertEquals(35.0, r2.getFontSize(), 0); lv2CPr.addNewLatin().setTypeface("Arial"); assertEquals("Arial", r2.getFontFamily()); lv2PPr.setAlgn(STTextAlignType.L); assertEquals(TextAlign.LEFT, p2.getTextAlign()); lv3CPr.setSz(3500); - assertEquals(35.0, r3.getFontSize()); + assertEquals(35.0, r3.getFontSize(), 0); lv3CPr.addNewLatin().setTypeface("Arial"); assertEquals("Arial", r3.getFontFamily()); lv3PPr.setAlgn(STTextAlignType.L); @@ -871,21 +873,21 @@ public class TestXSLFTextShape extends TestCase { lv3CPr = r3.getXmlObject().getRPr(); lv1CPr.setSz(3600); - assertEquals(36.0, r1.getFontSize()); + assertEquals(36.0, r1.getFontSize(), 0); lv1CPr.addNewLatin().setTypeface("Calibri"); assertEquals("Calibri", r1.getFontFamily()); lv1PPr.setAlgn(STTextAlignType.CTR); assertEquals(TextAlign.CENTER, p1.getTextAlign()); lv2CPr.setSz(3600); - assertEquals(36.0, r2.getFontSize()); + assertEquals(36.0, r2.getFontSize(), 0); lv2CPr.addNewLatin().setTypeface("Calibri"); assertEquals("Calibri", r2.getFontFamily()); lv2PPr.setAlgn(STTextAlignType.CTR); assertEquals(TextAlign.CENTER, p2.getTextAlign()); lv3CPr.setSz(3600); - assertEquals(36.0, r3.getFontSize()); + assertEquals(36.0, r3.getFontSize(), 0); lv3CPr.addNewLatin().setTypeface("Calibri"); assertEquals("Calibri", r3.getFontFamily()); lv3PPr.setAlgn(STTextAlignType.CTR); diff --git a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java index 650bfcd0cf..3e85f75c57 100644 --- a/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java +++ b/src/ooxml/testcases/org/apache/poi/xslf/usermodel/TestXSLFTheme.java @@ -16,32 +16,39 @@ ==================================================================== */ package org.apache.poi.xslf.usermodel; -import junit.framework.TestCase; -import org.apache.poi.xslf.XSLFTestDataSamples; +import static org.junit.Assert.*; import java.awt.Color; -import java.awt.TexturePaint; +import java.util.List; + +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.sl.usermodel.PaintStyle.GradientPaint; +import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; +import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; +import org.apache.poi.xslf.XSLFTestDataSamples; +import org.junit.Test; /** * test reading properties from a multi-theme and multi-master document * * @author Yegor Kozlov */ -public class TestXSLFTheme extends TestCase { +public class TestXSLFTheme { + @Test public void testRead(){ XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("themes.pptx"); - XSLFSlide[] slides = ppt.getSlides(); - - slide1(slides[0]); - slide2(slides[1]); - slide3(slides[2]); - slide4(slides[3]); - slide5(slides[4]); - slide6(slides[5]); - slide7(slides[6]); - slide8(slides[7]); - slide9(slides[8]); - slide10(slides[9]); + List slides = ppt.getSlides(); + + slide1(slides.get(0)); + slide2(slides.get(1)); + slide3(slides.get(2)); + slide4(slides.get(3)); + slide5(slides.get(4)); + slide6(slides.get(5)); + slide7(slides.get(6)); + slide8(slides.get(7)); + slide9(slides.get(8)); + slide10(slides.get(9)); } private XSLFShape getShape(XSLFSheet sheet, String name){ @@ -58,11 +65,10 @@ public class TestXSLFTheme extends TestCase { assertEquals("Office Theme", theme.getName()); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 3"); - RenderableShape rsh1 = new RenderableShape(sh1); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(Color.white, run1.getFontColor()); assertEquals(new Color(79, 129, 189), sh1.getFillColor()); - assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill + assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill } @@ -73,20 +79,19 @@ public class TestXSLFTheme extends TestCase { } void slide3(XSLFSlide slide){ - assertNull(slide.getBackground().getFillColor()); - assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof GradientPaint); } void slide4(XSLFSlide slide){ - assertNull(slide.getBackground().getFillColor()); - assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof GradientPaint); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Rectangle 4"); - RenderableShape rsh1 = new RenderableShape(sh1); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(Color.white, run1.getFontColor()); assertEquals(new Color(148, 198, 0), sh1.getFillColor()); - assertTrue(rsh1.getFillPaint(null) instanceof Color) ; // solid fill + assertTrue(sh1.getFillStyle().getPaint() instanceof SolidPaint) ; // solid fill XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 3"); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); @@ -97,14 +102,15 @@ public class TestXSLFTheme extends TestCase { } void slide5(XSLFSlide slide){ - assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof TexturePaint); XSLFTextShape sh2 = (XSLFTextShape)getShape(slide, "Title 1"); XSLFTextRun run2 = sh2.getTextParagraphs().get(0).getTextRuns().get(0); assertEquals(new Color(148, 198, 0), run2.getFontColor()); assertNull(sh2.getFillColor()); // no fill // font size is 40pt and scale factor is 90% - assertEquals(36.0, run2.getFontSize()); + assertEquals(36.0, run2.getFontSize(), 0); assertTrue(slide.getSlideLayout().getFollowMasterGraphics()); } @@ -133,15 +139,18 @@ public class TestXSLFTheme extends TestCase { } void slide8(XSLFSlide slide){ - assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof TexturePaint); } void slide9(XSLFSlide slide){ - assertTrue(slide.getBackground().getPaint(null) instanceof TexturePaint); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof TexturePaint); } void slide10(XSLFSlide slide){ - assertTrue(slide.getBackground().getPaint(null).getClass().getName().indexOf("Gradient") > 0); + PaintStyle fs = slide.getBackground().getFillStyle().getPaint(); + assertTrue(fs instanceof GradientPaint); XSLFTextShape sh1 = (XSLFTextShape)getShape(slide, "Title 3"); XSLFTextRun run1 = sh1.getTextParagraphs().get(0).getTextRuns().get(0); diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java b/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java index 6795601a6c..cfeffb8008 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/BitmapPainter.java @@ -18,13 +18,14 @@ package org.apache.poi.hslf.blip; import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.model.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogFactory; + /* ==================================================================== Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/DIB.java b/src/scratchpad/src/org/apache/poi/hslf/blip/DIB.java index 401ac43476..5eb8149b12 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/DIB.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/DIB.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.hslf.model.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; import org.apache.poi.util.LittleEndian; import java.io.IOException; @@ -35,7 +35,7 @@ public final class DIB extends Bitmap { /** * @return type of this picture - * @see org.apache.poi.hslf.model.HSLFPictureShape#DIB + * @see org.apache.poi.hslf.usermodel.HSLFPictureShape#DIB */ public int getType(){ return HSLFPictureShape.DIB; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java index 5fe55f1819..d7dadb6c5a 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/EMF.java @@ -17,8 +17,8 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.hslf.model.HSLFPictureShape; -import org.apache.poi.hslf.model.HSLFShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFShape; import org.apache.poi.hslf.exceptions.HSLFException; import java.io.ByteArrayOutputStream; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/ImagePainter.java b/src/scratchpad/src/org/apache/poi/hslf/blip/ImagePainter.java index 0f1afecb98..76359dc304 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/ImagePainter.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/ImagePainter.java @@ -17,8 +17,8 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.hslf.model.HSLFPictureShape; import org.apache.poi.hslf.usermodel.HSLFPictureData; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; import java.awt.*; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/JPEG.java b/src/scratchpad/src/org/apache/poi/hslf/blip/JPEG.java index 567fc996ee..08ba5ceb98 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/JPEG.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/JPEG.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.hslf.model.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; /** * Represents a JPEG picture data in a PPT file @@ -28,7 +28,7 @@ public final class JPEG extends Bitmap { /** * @return type of this picture - * @see org.apache.poi.hslf.model.HSLFPictureShape#JPEG + * @see org.apache.poi.hslf.usermodel.HSLFPictureShape#JPEG */ public int getType(){ return HSLFPictureShape.JPEG; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java index 9b2df64262..016c50f875 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PICT.java @@ -23,8 +23,8 @@ import java.io.IOException; import java.util.zip.InflaterInputStream; import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.hslf.model.HSLFPictureShape; -import org.apache.poi.hslf.model.HSLFShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFShape; /** * Represents Macintosh PICT picture data. @@ -102,7 +102,7 @@ public final class PICT extends Metafile { } /** - * @see org.apache.poi.hslf.model.HSLFPictureShape#PICT + * @see org.apache.poi.hslf.usermodel.HSLFPictureShape#PICT */ public int getType(){ return HSLFPictureShape.PICT; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java index a1d9aa50a9..114b736bfa 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/PNG.java @@ -17,7 +17,7 @@ package org.apache.poi.hslf.blip; -import org.apache.poi.hslf.model.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; import org.apache.poi.util.PngUtils; /** @@ -46,7 +46,7 @@ public final class PNG extends Bitmap { /** * @return type of this picture - * @see org.apache.poi.hslf.model.HSLFPictureShape#PNG + * @see org.apache.poi.hslf.usermodel.HSLFPictureShape#PNG */ public int getType(){ return HSLFPictureShape.PNG; diff --git a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java index 3270b32596..a84aed2e6f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java +++ b/src/scratchpad/src/org/apache/poi/hslf/blip/WMF.java @@ -19,8 +19,8 @@ package org.apache.poi.hslf.blip; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogger; -import org.apache.poi.hslf.model.HSLFPictureShape; -import org.apache.poi.hslf.model.HSLFShape; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; +import org.apache.poi.hslf.usermodel.HSLFShape; import org.apache.poi.hslf.exceptions.HSLFException; import java.io.*; diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/PPDrawingTextListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/PPDrawingTextListing.java index e437f9504e..c26e5cae1e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/PPDrawingTextListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/PPDrawingTextListing.java @@ -18,8 +18,8 @@ package org.apache.poi.hslf.dev; import org.apache.poi.hslf.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTListing.java index d0ab5ec98f..91d6086b1b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTListing.java @@ -17,11 +17,11 @@ package org.apache.poi.hslf.dev; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.RecordTypes; import org.apache.poi.hslf.record.SlideListWithText; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** * Uses record level code to Documents. diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTTextListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTTextListing.java index fc9b224801..0f4f5db60b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTTextListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/SLWTTextListing.java @@ -18,8 +18,8 @@ package org.apache.poi.hslf.dev; import org.apache.poi.hslf.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** * Uses record level code to locate SlideListWithText entries. diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideAndNotesAtomListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideAndNotesAtomListing.java index 2a69c17d81..44c2cd8b4a 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideAndNotesAtomListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideAndNotesAtomListing.java @@ -18,8 +18,8 @@ package org.apache.poi.hslf.dev; import org.apache.poi.hslf.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideIdListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideIdListing.java index b4f487ab8a..1398175f42 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideIdListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideIdListing.java @@ -20,7 +20,6 @@ package org.apache.poi.hslf.dev; import java.io.ByteArrayOutputStream; import java.util.Map; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.Document; import org.apache.poi.hslf.record.Notes; import org.apache.poi.hslf.record.NotesAtom; @@ -32,6 +31,7 @@ import org.apache.poi.hslf.record.SlideAtom; import org.apache.poi.hslf.record.SlideListWithText; import org.apache.poi.hslf.record.SlidePersistAtom; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.util.LittleEndian; /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideShowRecordDumper.java b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideShowRecordDumper.java index 77415ff2dc..45ededed15 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/SlideShowRecordDumper.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/SlideShowRecordDumper.java @@ -21,7 +21,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Iterator; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.Record; import org.apache.poi.util.HexDump; import org.apache.poi.ddf.DefaultEscherRecordFactory; @@ -32,6 +31,7 @@ import org.apache.poi.hslf.record.EscherTextboxWrapper; import org.apache.poi.hslf.record.TextCharsAtom; import org.apache.poi.hslf.record.TextBytesAtom; import org.apache.poi.hslf.record.StyleTextPropAtom; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** * This class provides a way to view the contents of a powerpoint file. diff --git a/src/scratchpad/src/org/apache/poi/hslf/dev/TextStyleListing.java b/src/scratchpad/src/org/apache/poi/hslf/dev/TextStyleListing.java index d7fcbc6fd1..14b7706fbd 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/dev/TextStyleListing.java +++ b/src/scratchpad/src/org/apache/poi/hslf/dev/TextStyleListing.java @@ -17,14 +17,11 @@ package org.apache.poi.hslf.dev; -import org.apache.poi.hslf.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; -import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; -import org.apache.poi.hslf.record.*; +import java.util.List; -import java.util.LinkedList; +import org.apache.poi.hslf.model.textproperties.*; +import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; /** * Uses record level code to locate StyleTextPropAtom entries. @@ -73,19 +70,19 @@ public final class TextStyleListing { public static void showStyleTextPropAtom(StyleTextPropAtom stpa) { System.out.println("\nFound a StyleTextPropAtom"); - LinkedList paragraphStyles = stpa.getParagraphStyles(); + List paragraphStyles = stpa.getParagraphStyles(); System.out.println("Contains " + paragraphStyles.size() + " paragraph styles:"); for(int i=0; i charStyles = stpa.getCharacterStyles(); System.out.println("Contains " + charStyles.size() + " character styles:"); for(int i=0; i textProps = tpc.getTextPropList(); System.out.println(" Contains " + textProps.size() + " TextProps"); for(int i=0; i _slides; private boolean _slidesByDefault = true; private boolean _notesByDefault = false; @@ -74,6 +68,7 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { PowerPointExtractor ppe = new PowerPointExtractor(file); System.out.println(ppe.getText(true, notes, comments, master)); + ppe.close(); } /** @@ -188,13 +183,10 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { public List getOLEShapes() { List list = new ArrayList(); - for (int i = 0; i < _slides.length; i++) { - HSLFSlide slide = _slides[i]; - - HSLFShape[] shapes = slide.getShapes(); - for (int j = 0; j < shapes.length; j++) { - if (shapes[j] instanceof OLEShape) { - list.add((OLEShape) shapes[j]); + for (HSLFSlide slide : _slides) { + for (HSLFShape shape : slide.getShapes()) { + if (shape instanceof OLEShape) { + list.add((OLEShape) shape); } } } @@ -219,7 +211,7 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { if (getSlideText) { if (getMasterText) { - for (SlideMaster master : _show.getSlidesMasters()) { + for (HSLFSlideMaster master : _show.getSlideMasters()) { for(HSLFShape sh : master.getShapes()){ if(sh instanceof HSLFTextShape){ if(HSLFMasterSheet.isPlaceholder(sh)) { @@ -241,8 +233,8 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { } } - for (int i = 0; i < _slides.length; i++) { - HSLFSlide slide = _slides[i]; + for (int i = 0; i < _slides.size(); i++) { + HSLFSlide slide = _slides.get(i); // Slide header, if set HeadersFooters hf = slide.getHeadersFooters(); @@ -251,7 +243,7 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { } // Slide text - textRunsToText(ret, slide.getTextRuns()); + textRunsToText(ret, slide.getTextParagraphs()); // Table text for (HSLFShape shape : slide.getShapes()){ @@ -284,8 +276,8 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { HashSet seenNotes = new HashSet(); HeadersFooters hf = _show.getNotesHeadersFooters(); - for (int i = 0; i < _slides.length; i++) { - HSLFNotes notes = _slides[i].getNotesSheet(); + for (int i = 0; i < _slides.size(); i++) { + HSLFNotes notes = _slides.get(i).getNotes(); if (notes == null) { continue; } @@ -301,7 +293,7 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { } // Notes text - textRunsToText(ret, notes.getTextRuns()); + textRunsToText(ret, notes.getTextParagraphs()); // Repeat the notes footer, if set if (hf != null && hf.isFooterVisible() && hf.getFooterText() != null) { @@ -330,17 +322,17 @@ public final class PowerPointExtractor extends POIOLE2TextExtractor { ret.append('\n'); } } - private void textRunsToText(StringBuffer ret, HSLFTextParagraph[] runs) { - if (runs==null) { + private void textRunsToText(StringBuffer ret, List> paragraphs) { + if (paragraphs==null) { return; } - for (int j = 0; j < runs.length; j++) { - HSLFTextParagraph run = runs[j]; - if (run != null) { - String text = run.getText(); - ret.append(text); - if (!text.endsWith("\n")) { + for (List lp : paragraphs) { + for (HSLFTextParagraph p : lp) { + for (HSLFTextRun r : p.getTextRuns()) { + ret.append(r.getRawText()); + } + if (ret.length() > 0 && ret.charAt(ret.length()-1) != '\n') { ret.append("\n"); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/extractor/QuickButCruddyTextExtractor.java b/src/scratchpad/src/org/apache/poi/hslf/extractor/QuickButCruddyTextExtractor.java index 9c92c5c591..260eebd60f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/extractor/QuickButCruddyTextExtractor.java +++ b/src/scratchpad/src/org/apache/poi/hslf/extractor/QuickButCruddyTextExtractor.java @@ -17,20 +17,13 @@ package org.apache.poi.hslf.extractor; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.util.ArrayList; import java.util.List; -import org.apache.poi.hslf.model.HSLFTextParagraph; -import org.apache.poi.hslf.record.CString; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordTypes; -import org.apache.poi.hslf.record.StyleTextPropAtom; -import org.apache.poi.hslf.record.TextBytesAtom; -import org.apache.poi.hslf.record.TextCharsAtom; -import org.apache.poi.hslf.record.TextHeaderAtom; +import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFTextParagraph; +import org.apache.poi.hslf.usermodel.HSLFTextShape; import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.LittleEndian; @@ -174,18 +167,19 @@ public final class QuickButCruddyTextExtractor { } // Otherwise, check the type to see if it's text - long type = LittleEndian.getUShort(pptContents,startPos+2); - HSLFTextParagraph trun = null; + int type = LittleEndian.getUShort(pptContents,startPos+2); // TextBytesAtom if(type == RecordTypes.TextBytesAtom.typeID) { TextBytesAtom tba = (TextBytesAtom)Record.createRecordForType(type, pptContents, startPos, len+8); - trun = new HSLFTextParagraph((TextHeaderAtom)null,tba,(StyleTextPropAtom)null); + String text = HSLFTextParagraph.toExternalString(tba.getText(), -1); + textV.add(text); } // TextCharsAtom if(type == RecordTypes.TextCharsAtom.typeID) { TextCharsAtom tca = (TextCharsAtom)Record.createRecordForType(type, pptContents, startPos, len+8); - trun = new HSLFTextParagraph((TextHeaderAtom)null,tca,(StyleTextPropAtom)null); + String text = HSLFTextParagraph.toExternalString(tca.getText(), -1); + textV.add(text); } // CString (doesn't go via a TextRun) @@ -201,10 +195,6 @@ public final class QuickButCruddyTextExtractor { } } - // If we found text via a TextRun, save it in the vector - if(trun != null) { - textV.add(trun.getText()); - } // Wind on by the atom length, and check we're not at the end int newPos = (startPos + 8 + len); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java index 95f83a3834..567b8297e0 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ActiveXShape.java @@ -34,6 +34,7 @@ import org.apache.poi.hslf.record.ExObjList; import org.apache.poi.hslf.record.OEShapeAtom; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.RecordTypes; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.util.LittleEndian; diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java deleted file mode 100644 index 0afc71076b..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java +++ /dev/null @@ -1,388 +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 java.awt.geom.AffineTransform; -import java.awt.geom.Arc2D; -import java.awt.geom.Ellipse2D; -import java.awt.geom.GeneralPath; -import java.awt.geom.Line2D; -import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; - -import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.sl.usermodel.ShapeType; - -/** - * Stores definition of auto-shapes. - * See the Office Drawing 97-2007 Binary Format Specification for details. - * - * TODO: follow the spec and define all the auto-shapes - * - * @author Yegor Kozlov - */ -public final class AutoShapes { - protected static final ShapeOutline[] shapes; - - - /** - * Return shape outline by shape type - * @param type shape type see {@link ShapeTypes} - * - * @return the shape outline - */ - public static ShapeOutline getShapeOutline(ShapeType type){ - ShapeOutline outline = shapes[type.nativeId]; - return outline; - } - - /** - * Auto-shapes are defined in the [0,21600] coordinate system. - * We need to transform it into normal slide coordinates - * - */ - public static java.awt.Shape transform(java.awt.Shape outline, Rectangle2D anchor){ - AffineTransform at = new AffineTransform(); - at.translate(anchor.getX(), anchor.getY()); - at.scale( - 1.0f/21600*anchor.getWidth(), - 1.0f/21600*anchor.getHeight() - ); - return at.createTransformedShape(outline); - } - - static { - shapes = new ShapeOutline[255]; - - shapes[ShapeType.RECT.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - Rectangle2D path = new Rectangle2D.Float(0, 0, 21600, 21600); - return path; - } - }; - - shapes[ShapeType.ROUND_RECT.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - RoundRectangle2D path = new RoundRectangle2D.Float(0, 0, 21600, 21600, adjval, adjval); - return path; - } - }; - - shapes[ShapeType.ELLIPSE.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - Ellipse2D path = new Ellipse2D.Float(0, 0, 21600, 21600); - return path; - } - }; - - shapes[ShapeType.DIAMOND.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - GeneralPath path = new GeneralPath(); - path.moveTo(10800, 0); - path.lineTo(21600, 10800); - path.lineTo(10800, 21600); - path.lineTo(0, 10800); - path.closePath(); - return path; - } - }; - - //m@0,l,21600r21600 - shapes[ShapeType.TRIANGLE.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 10800); - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(0, 21600); - path.lineTo(21600, 21600); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.RT_TRIANGLE.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - GeneralPath path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(21600, 21600); - path.lineTo(0, 21600); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.PARALLELOGRAM.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(21600, 0); - path.lineTo(21600 - adjval, 21600); - path.lineTo(0, 21600); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.TRAPEZOID.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - - GeneralPath path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(adjval, 21600); - path.lineTo(21600 - adjval, 21600); - path.lineTo(21600, 0); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.HEXAGON.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(21600 - adjval, 0); - path.lineTo(21600, 10800); - path.lineTo(21600 - adjval, 21600); - path.lineTo(adjval, 21600); - path.lineTo(0, 10800); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.OCTAGON.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 6326); - - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(21600 - adjval, 0); - path.lineTo(21600, adjval); - path.lineTo(21600, 21600-adjval); - path.lineTo(21600-adjval, 21600); - path.lineTo(adjval, 21600); - path.lineTo(0, 21600-adjval); - path.lineTo(0, adjval); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.PLUS.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(21600 - adjval, 0); - path.lineTo(21600 - adjval, adjval); - path.lineTo(21600, adjval); - path.lineTo(21600, 21600-adjval); - path.lineTo(21600-adjval, 21600-adjval); - path.lineTo(21600-adjval, 21600); - path.lineTo(adjval, 21600); - path.lineTo(adjval, 21600-adjval); - path.lineTo(0, 21600-adjval); - path.lineTo(0, adjval); - path.lineTo(adjval, adjval); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.PENTAGON.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - - GeneralPath path = new GeneralPath(); - path.moveTo(10800, 0); - path.lineTo(21600, 8259); - path.lineTo(21600 - 4200, 21600); - path.lineTo(4200, 21600); - path.lineTo(0, 8259); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.DOWN_ARROW.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m0@0 l@1@0 @1,0 @2,0 @2@0,21600@0,10800,21600xe - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400); - GeneralPath path = new GeneralPath(); - path.moveTo(0, adjval); - path.lineTo(adjval2, adjval); - path.lineTo(adjval2, 0); - path.lineTo(21600-adjval2, 0); - path.lineTo(21600-adjval2, adjval); - path.lineTo(21600, adjval); - path.lineTo(10800, 21600); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.UP_ARROW.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m0@0 l@1@0 @1,21600@2,21600@2@0,21600@0,10800,xe - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400); - GeneralPath path = new GeneralPath(); - path.moveTo(0, adjval); - path.lineTo(adjval2, adjval); - path.lineTo(adjval2, 21600); - path.lineTo(21600-adjval2, 21600); - path.lineTo(21600-adjval2, adjval); - path.lineTo(21600, adjval); - path.lineTo(10800, 0); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.RIGHT_ARROW.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m@0, l@0@1 ,0@1,0@2@0@2@0,21600,21600,10800xe - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 16200); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400); - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(adjval, adjval2); - path.lineTo(0, adjval2); - path.lineTo(0, 21600-adjval2); - path.lineTo(adjval, 21600-adjval2); - path.lineTo(adjval, 21600); - path.lineTo(21600, 10800); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.LEFT_ARROW.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m@0, l@0@1,21600@1,21600@2@0@2@0,21600,,10800xe - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 5400); - GeneralPath path = new GeneralPath(); - path.moveTo(adjval, 0); - path.lineTo(adjval, adjval2); - path.lineTo(21600, adjval2); - path.lineTo(21600, 21600-adjval2); - path.lineTo(adjval, 21600-adjval2); - path.lineTo(adjval, 21600); - path.lineTo(0, 10800); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.CAN.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m10800,qx0@1l0@2qy10800,21600,21600@2l21600@1qy10800,xem0@1qy10800@0,21600@1nfe - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 5400); - - GeneralPath path = new GeneralPath(); - - path.append(new Arc2D.Float(0, 0, 21600, adjval, 0, 180, Arc2D.OPEN), false); - path.moveTo(0, adjval/2); - - path.lineTo(0, 21600 - adjval/2); - path.closePath(); - - path.append(new Arc2D.Float(0, 21600 - adjval, 21600, adjval, 180, 180, Arc2D.OPEN), false); - path.moveTo(21600, 21600 - adjval/2); - - path.lineTo(21600, adjval/2); - path.append(new Arc2D.Float(0, 0, 21600, adjval, 180, 180, Arc2D.OPEN), false); - path.moveTo(0, adjval/2); - path.closePath(); - return path; - } - }; - - shapes[ShapeType.LEFT_BRACE.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m21600,qx10800@0l10800@2qy0@11,10800@3l10800@1qy21600,21600e - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800); - - GeneralPath path = new GeneralPath(); - path.moveTo(21600, 0); - - path.append(new Arc2D.Float(10800, 0, 21600, adjval*2, 90, 90, Arc2D.OPEN), false); - path.moveTo(10800, adjval); - - path.lineTo(10800, adjval2 - adjval); - - path.append(new Arc2D.Float(-10800, adjval2 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false); - path.moveTo(0, adjval2); - - path.append(new Arc2D.Float(-10800, adjval2, 21600, adjval*2, 0, 90, Arc2D.OPEN), false); - path.moveTo(10800, adjval2 + adjval); - - path.lineTo(10800, 21600 - adjval); - - path.append(new Arc2D.Float(10800, 21600 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false); - - return path; - } - }; - - shapes[ShapeType.RIGHT_BRACE.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - //m,qx10800@0 l10800@2qy21600@11,10800@3l10800@1qy,21600e - int adjval = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUSTVALUE, 1800); - int adjval2 = shape.getEscherProperty(EscherProperties.GEOMETRY__ADJUST2VALUE, 10800); - - GeneralPath path = new GeneralPath(); - path.moveTo(0, 0); - - path.append(new Arc2D.Float(-10800, 0, 21600, adjval*2, 0, 90, Arc2D.OPEN), false); - path.moveTo(10800, adjval); - - path.lineTo(10800, adjval2 - adjval); - - path.append(new Arc2D.Float(10800, adjval2 - 2*adjval, 21600, adjval*2, 180, 90, Arc2D.OPEN), false); - path.moveTo(21600, adjval2); - - path.append(new Arc2D.Float(10800, adjval2, 21600, adjval*2, 90, 90, Arc2D.OPEN), false); - path.moveTo(10800, adjval2 + adjval); - - path.lineTo(10800, 21600 - adjval); - - path.append(new Arc2D.Float(-10800, 21600 - 2*adjval, 21600, adjval*2, 270, 90, Arc2D.OPEN), false); - - return path; - } - }; - - shapes[ShapeType.STRAIGHT_CONNECTOR_1.nativeId] = new ShapeOutline(){ - public java.awt.Shape getOutline(HSLFShape shape){ - return new Line2D.Float(0, 0, 21600, 21600); - } - }; - - - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFAutoShape.java deleted file mode 100644 index 1f74f2ceb5..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFAutoShape.java +++ /dev/null @@ -1,123 +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.sl.draw.geom.CustomGeometry; -import org.apache.poi.sl.draw.geom.Guide; -import org.apache.poi.sl.usermodel.*; -import org.apache.poi.util.POILogger; - -import java.awt.geom.Rectangle2D; -import java.util.Iterator; - -/** - * Represents an AutoShape. - *

- * AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments. - * See {@link ShapeTypes} - *

- * - * @author Yegor Kozlov - */ -public class HSLFAutoShape extends HSLFTextShape implements AutoShape { - - protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - } - - public HSLFAutoShape(ShapeType type, ShapeContainer parent){ - super(null, parent); - _escherContainer = createSpContainer(type, parent instanceof HSLFGroupShape); - } - - public HSLFAutoShape(ShapeType type){ - this(type, null); - } - - protected EscherContainerRecord createSpContainer(ShapeType shapeType, boolean isChild){ - _escherContainer = super.createSpContainer(isChild); - - setShapeType(shapeType); - - //set default properties for an autoshape - setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000); - setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); - setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); - setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000); - setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010); - setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001); - setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008); - setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); - - return _escherContainer; - } - - protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ - setVerticalAlignment(HSLFTextBox.AnchorMiddle); - setHorizontalAlignment(HSLFTextBox.AlignCenter); - setWordWrap(HSLFTextBox.WrapNone); - } - - /** - * Gets adjust value which controls smart resizing of the auto-shape. - * - *

- * The adjustment values are given in shape coordinates: - * the origin is at the top-left, positive-x is to the right, positive-y is down. - * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant). - *

- * - * @param idx the adjust index in the [0, 9] range - * @return the adjustment value - */ - public int getAdjustmentValue(int idx){ - if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range"); - - return getEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx)); - } - - /** - * Sets adjust value which controls smart resizing of the auto-shape. - * - *

- * The adjustment values are given in shape coordinates: - * the origin is at the top-left, positive-x is to the right, positive-y is down. - * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant). - *

- * - * @param idx the adjust index in the [0, 9] range - * @param val the adjustment value - */ - public void setAdjustmentValue(int idx, int val){ - if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range"); - - setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val); - } - - public java.awt.Shape getOutline(){ - ShapeOutline outline = AutoShapes.getShapeOutline(getShapeType()); - Rectangle2D anchor = getLogicalAnchor2D(); - if(outline == null){ - logger.log(POILogger.WARN, "Outline not found for " + getShapeType().nativeName); - return anchor; - } - java.awt.Shape shape = outline.getOutline(this); - return AutoShapes.transform(shape, anchor); - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFBackground.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFBackground.java deleted file mode 100644 index 8d581f5f35..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFBackground.java +++ /dev/null @@ -1,38 +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.EscherContainerRecord; -import org.apache.poi.sl.usermodel.Background; -import org.apache.poi.sl.usermodel.ShapeContainer; - -/** - * Background shape - * - * @author Yegor Kozlov - */ -public final class HSLFBackground extends HSLFShape implements Background { - - protected HSLFBackground(EscherContainerRecord escherRecord, ShapeContainer parent) { - super(escherRecord, parent); - } - - protected EscherContainerRecord createSpContainer(boolean isChild) { - return null; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFill.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFill.java deleted file mode 100644 index 14846e1ea0..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFill.java +++ /dev/null @@ -1,312 +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 java.awt.Color; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.List; - -import org.apache.poi.ddf.*; -import org.apache.poi.hslf.record.Document; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.*; -import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; -import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint. - * - * @author Yegor Kozlov - */ -public final class HSLFFill { - // For logging - protected POILogger logger = POILogFactory.getLogger(this.getClass()); - - /** - * Fill with a solid color - */ - public static final int FILL_SOLID = 0; - - /** - * Fill with a pattern (bitmap) - */ - public static final int FILL_PATTERN = 1; - - /** - * A texture (pattern with its own color map) - */ - public static final int FILL_TEXTURE = 2; - - /** - * Center a picture in the shape - */ - public static final int FILL_PICTURE = 3; - - /** - * Shade from start to end points - */ - public static final int FILL_SHADE = 4; - - /** - * Shade from bounding rectangle to end point - */ - public static final int FILL_SHADE_CENTER = 5; - - /** - * Shade from shape outline to end point - */ - public static final int FILL_SHADE_SHAPE = 6; - - /** - * Similar to FILL_SHADE, but the fill angle - * is additionally scaled by the aspect ratio of - * the shape. If shape is square, it is the same as FILL_SHADE - */ - public static final int FILL_SHADE_SCALE = 7; - - /** - * shade to title - */ - public static final int FILL_SHADE_TITLE = 8; - - /** - * Use the background fill color/pattern - */ - public static final int FILL_BACKGROUND = 9; - - - - /** - * The shape this background applies to - */ - protected HSLFShape shape; - - /** - * Construct a Fill object for a shape. - * Fill information will be read from shape's escher properties. - * - * @param shape the shape this background applies to - */ - public HSLFFill(HSLFShape shape){ - this.shape = shape; - } - - - public FillStyle getFillStyle() { - return new FillStyle() { - public PaintStyle getPaint() { - switch (getFillType()) { - case FILL_SOLID: { - return new SolidPaint() { - public ColorStyle getSolidColor() { - return new ColorStyle() { - public Color getColor() { return getForegroundColor(); } - public int getAlpha() { return -1; } - public int getLumOff() { return -1; } - public int getLumMod() { return -1; } - public int getShade() { return -1; } - public int getTint() { return -1; } - }; - } - }; - } - case FILL_PICTURE: { - return new TexturePaint() { - final HSLFPictureData pd = getPictureData(); - - public InputStream getImageData() { - return new ByteArrayInputStream(pd.getData()); - } - - public String getContentType() { - return pd.getContentType(); - } - - public int getAlpha() { - return (int)(shape.getAlpha(EscherProperties.FILL__FILLOPACITY)*100000.0); - } - }; - } - default: - logger.log(POILogger.WARN, "unsuported fill type: " + getFillType()); - break; - } - return PaintStyle.TRANSPARENT_PAINT; - } - }; - } - - /** - * Returns fill type. - * Must be one of the FILL_* constants defined in this class. - * - * @return type of fill - */ - public int getFillType(){ - EscherOptRecord opt = shape.getEscherOptRecord(); - EscherSimpleProperty prop = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE); - return prop == null ? FILL_SOLID : prop.getPropertyValue(); - } - - /** - */ - protected void afterInsert(HSLFSheet sh){ - EscherOptRecord opt = shape.getEscherOptRecord(); - EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE); - if(p != null) { - int idx = p.getPropertyValue(); - EscherBSERecord bse = getEscherBSERecord(idx); - bse.setRef(bse.getRef() + 1); - } - } - - protected EscherBSERecord getEscherBSERecord(int idx){ - HSLFSheet sheet = shape.getSheet(); - if(sheet == null) { - logger.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet"); - return null; - } - HSLFSlideShow ppt = sheet.getSlideShow(); - Document doc = ppt.getDocumentRecord(); - EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); - EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); - if(bstore == null) { - logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found "); - return null; - } - List lst = bstore.getChildRecords(); - return (EscherBSERecord)lst.get(idx-1); - } - - /** - * Sets fill type. - * Must be one of the FILL_* constants defined in this class. - * - * @param type type of the fill - */ - public void setFillType(int type){ - EscherOptRecord opt = shape.getEscherOptRecord(); - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLTYPE, type); - } - - /** - * Foreground color - */ - public Color getForegroundColor(){ - EscherOptRecord opt = shape.getEscherOptRecord(); - EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); - - if(p != null && (p.getPropertyValue() & 0x10) == 0) return null; - - return shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1); - - } - - /** - * Foreground color - */ - public void setForegroundColor(Color color){ - EscherOptRecord opt = shape.getEscherOptRecord(); - if (color == null) { - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000); - } - else { - int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb); - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011); - } - } - - /** - * Background color - */ - public Color getBackgroundColor(){ - EscherOptRecord opt = shape.getEscherOptRecord(); - EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); - - if(p != null && (p.getPropertyValue() & 0x10) == 0) return null; - - return shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1); - } - - /** - * Background color - */ - public void setBackgroundColor(Color color){ - EscherOptRecord opt = shape.getEscherOptRecord(); - if (color == null) { - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, -1); - } - else { - int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); - HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, rgb); - } - } - - /** - * PictureData object used in a texture, pattern of picture fill. - */ - public HSLFPictureData getPictureData(){ - EscherOptRecord opt = shape.getEscherOptRecord(); - EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE); - if (p == null) return null; - - HSLFSlideShow ppt = shape.getSheet().getSlideShow(); - HSLFPictureData[] pict = ppt.getPictureData(); - Document doc = ppt.getDocumentRecord(); - - EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); - EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); - - java.util.List lst = bstore.getChildRecords(); - int idx = p.getPropertyValue(); - if (idx == 0){ - logger.log(POILogger.WARN, "no reference to picture data found "); - } else { - EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1); - for ( int i = 0; i < pict.length; i++ ) { - if (pict[i].getOffset() == bse.getOffset()){ - return pict[i]; - } - } - } - - return null; - } - - /** - * Assign picture used to fill the underlying shape. - * - * @param idx 0-based index of the picture added to this ppt by SlideShow.addPicture method. - */ - public void setPictureData(int idx){ - EscherOptRecord opt = shape.getEscherOptRecord(); - HSLFShape.setEscherProperty(opt, (short)(EscherProperties.FILL__PATTERNTEXTURE + 0x4000), idx); - if( idx != 0 ) { - if( shape.getSheet() != null ) { - EscherBSERecord bse = getEscherBSERecord(idx); - bse.setRef(bse.getRef() + 1); - } - } - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFreeformShape.java deleted file mode 100644 index 685e2dad2f..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFFreeformShape.java +++ /dev/null @@ -1,264 +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 java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -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.EscherSimpleProperty; -import org.apache.poi.sl.usermodel.ShapeContainer; -import org.apache.poi.sl.usermodel.ShapeType; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.POILogger; - -/** - * A "Freeform" shape. - * - *

- * Shapes drawn with the "Freeform" tool have cubic bezier curve segments in the smooth sections - * and straight-line segments in the straight sections. This object closely corresponds to java.awt.geom.GeneralPath. - *

- * @author Yegor Kozlov - */ -public final class HSLFFreeformShape extends HSLFAutoShape { - - public static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40}; - public static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC}; - public static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00}; - public static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20}; - public static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD}; - public static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3}; //OpenOffice inserts 0xB3 instead of 0xAD. - public static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60}; - public static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80}; - - /** - * Create a Freeform object and initialize it from the supplied Record container. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of the shape - */ - protected HSLFFreeformShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - - } - - /** - * Create a new Freeform. This constructor is used when a new shape is created. - * - * @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 HSLFFreeformShape(ShapeContainer parent){ - super((EscherContainerRecord)null, parent); - _escherContainer = createSpContainer(ShapeType.NOT_PRIMITIVE, parent instanceof HSLFGroupShape); - } - - /** - * Create a new Freeform. This constructor is used when a new shape is created. - * - */ - public HSLFFreeformShape(){ - this(null); - } - - /** - * Set the shape path - * - * @param path - */ - public void setPath(GeneralPath path) - { - Rectangle2D bounds = path.getBounds2D(); - PathIterator it = path.getPathIterator(new AffineTransform()); - - List segInfo = new ArrayList(); - List pntInfo = new ArrayList(); - boolean isClosed = false; - while (!it.isDone()) { - double[] vals = new double[6]; - int type = it.currentSegment(vals); - switch (type) { - case PathIterator.SEG_MOVETO: - pntInfo.add(new Point2D.Double(vals[0], vals[1])); - segInfo.add(SEGMENTINFO_MOVETO); - break; - case PathIterator.SEG_LINETO: - pntInfo.add(new Point2D.Double(vals[0], vals[1])); - segInfo.add(SEGMENTINFO_LINETO); - segInfo.add(SEGMENTINFO_ESCAPE); - break; - case PathIterator.SEG_CUBICTO: - pntInfo.add(new Point2D.Double(vals[0], vals[1])); - pntInfo.add(new Point2D.Double(vals[2], vals[3])); - pntInfo.add(new Point2D.Double(vals[4], vals[5])); - segInfo.add(SEGMENTINFO_CUBICTO); - segInfo.add(SEGMENTINFO_ESCAPE2); - break; - case PathIterator.SEG_QUADTO: - //TODO: figure out how to convert SEG_QUADTO into SEG_CUBICTO - logger.log(POILogger.WARN, "SEG_QUADTO is not supported"); - break; - case PathIterator.SEG_CLOSE: - pntInfo.add(pntInfo.get(0)); - segInfo.add(SEGMENTINFO_LINETO); - segInfo.add(SEGMENTINFO_ESCAPE); - segInfo.add(SEGMENTINFO_LINETO); - segInfo.add(SEGMENTINFO_CLOSE); - isClosed = true; - break; - } - - it.next(); - } - if(!isClosed) segInfo.add(SEGMENTINFO_LINETO); - segInfo.add(new byte[]{0x00, (byte)0x80}); - - EscherOptRecord opt = getEscherOptRecord(); - opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4)); - - EscherArrayProperty verticesProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__VERTICES + 0x4000), false, null); - verticesProp.setNumberOfElementsInArray(pntInfo.size()); - verticesProp.setNumberOfElementsInMemory(pntInfo.size()); - verticesProp.setSizeOfElements(0xFFF0); - for (int i = 0; i < pntInfo.size(); i++) { - Point2D.Double pnt = pntInfo.get(i); - byte[] data = new byte[4]; - LittleEndian.putShort(data, 0, (short)((pnt.getX() - bounds.getX())*MASTER_DPI/POINT_DPI)); - LittleEndian.putShort(data, 2, (short)((pnt.getY() - bounds.getY())*MASTER_DPI/POINT_DPI)); - verticesProp.setElement(i, data); - } - opt.addEscherProperty(verticesProp); - - EscherArrayProperty segmentsProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000), false, null); - segmentsProp.setNumberOfElementsInArray(segInfo.size()); - segmentsProp.setNumberOfElementsInMemory(segInfo.size()); - segmentsProp.setSizeOfElements(0x2); - for (int i = 0; i < segInfo.size(); i++) { - byte[] seg = segInfo.get(i); - segmentsProp.setElement(i, seg); - } - opt.addEscherProperty(segmentsProp); - - opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__RIGHT, (int)(bounds.getWidth()*MASTER_DPI/POINT_DPI))); - opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__BOTTOM, (int)(bounds.getHeight()*MASTER_DPI/POINT_DPI))); - - opt.sortProperties(); - - setAnchor(bounds); - } - - /** - * Gets the freeform path - * - * @return the freeform path - */ - public GeneralPath getPath(){ - EscherOptRecord opt = getEscherOptRecord(); - opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4)); - - EscherArrayProperty verticesProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000)); - if(verticesProp == null) verticesProp = getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES); - - EscherArrayProperty segmentsProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000)); - if(segmentsProp == null) segmentsProp = getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO); - - //sanity check - if(verticesProp == null) { - logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES "); - return null; - } - if(segmentsProp == null) { - logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO "); - return null; - } - - GeneralPath path = new GeneralPath(); - int numPoints = verticesProp.getNumberOfElementsInArray(); - int numSegments = segmentsProp.getNumberOfElementsInArray(); - for (int i = 0, j = 0; i < numSegments && j < numPoints; i++) { - byte[] elem = segmentsProp.getElement(i); - if(Arrays.equals(elem, SEGMENTINFO_MOVETO)){ - byte[] p = verticesProp.getElement(j++); - short x = LittleEndian.getShort(p, 0); - short y = LittleEndian.getShort(p, 2); - path.moveTo( - ((float)x*POINT_DPI/MASTER_DPI), - ((float)y*POINT_DPI/MASTER_DPI)); - } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){ - i++; - byte[] p1 = verticesProp.getElement(j++); - short x1 = LittleEndian.getShort(p1, 0); - short y1 = LittleEndian.getShort(p1, 2); - byte[] p2 = verticesProp.getElement(j++); - short x2 = LittleEndian.getShort(p2, 0); - short y2 = LittleEndian.getShort(p2, 2); - byte[] p3 = verticesProp.getElement(j++); - short x3 = LittleEndian.getShort(p3, 0); - short y3 = LittleEndian.getShort(p3, 2); - path.curveTo( - ((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI), - ((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI), - ((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI)); - - } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){ - i++; - byte[] pnext = segmentsProp.getElement(i); - if(Arrays.equals(pnext, SEGMENTINFO_ESCAPE)){ - if(j + 1 < numPoints){ - byte[] p = verticesProp.getElement(j++); - short x = LittleEndian.getShort(p, 0); - short y = LittleEndian.getShort(p, 2); - path.lineTo( - ((float)x*POINT_DPI/MASTER_DPI), ((float)y*POINT_DPI/MASTER_DPI)); - } - } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){ - path.closePath(); - } - } - } - return path; - } - - public java.awt.Shape getOutline(){ - GeneralPath path = getPath(); - if(path == null) { - // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188 - return new GeneralPath(); - } - - Rectangle2D anchor = getAnchor2D(); - Rectangle2D bounds = path.getBounds2D(); - AffineTransform at = new AffineTransform(); - at.translate(anchor.getX(), anchor.getY()); - at.scale( - anchor.getWidth()/bounds.getWidth(), - anchor.getHeight()/bounds.getHeight() - ); - return at.createTransformedShape(path); - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFGroupShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFGroupShape.java deleted file mode 100644 index 64d4de28b4..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFGroupShape.java +++ /dev/null @@ -1,314 +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 java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.poi.ddf.EscherChildAnchorRecord; -import org.apache.poi.ddf.EscherClientAnchorRecord; -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.ddf.EscherSpRecord; -import org.apache.poi.ddf.EscherSpgrRecord; -import org.apache.poi.sl.usermodel.ShapeContainer; -import org.apache.poi.sl.usermodel.ShapeType; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.POILogger; - -/** - * Represents a group of shapes. - * - * @author Yegor Kozlov - */ -public class HSLFGroupShape extends HSLFShape implements ShapeContainer { - - /** - * Create a new ShapeGroup. This constructor is used when a new shape is created. - * - */ - public HSLFGroupShape(){ - this(null, null); - _escherContainer = createSpContainer(false); - } - - /** - * Create a ShapeGroup object and initilize it from the supplied Record container. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of the shape - */ - protected HSLFGroupShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - } - - /** - * @return the shapes contained in this group container - */ - public HSLFShape[] getShapes() { - List shapeList = getShapeList(); - HSLFShape[] shapes = shapeList.toArray(new HSLFShape[shapeList.size()]); - return shapes; - } - - /** - * 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){ - - 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)(anchor.y*MASTER_DPI/POINT_DPI)); - clientAnchor.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI)); - clientAnchor.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI)); - clientAnchor.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI)); - - EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); - - spgr.setRectX1(anchor.x*MASTER_DPI/POINT_DPI); - spgr.setRectY1(anchor.y*MASTER_DPI/POINT_DPI); - spgr.setRectX2((anchor.x + anchor.width)*MASTER_DPI/POINT_DPI); - spgr.setRectY2((anchor.y + anchor.height)*MASTER_DPI/POINT_DPI); - } - - /** - * Sets the coordinate space of this group. All children are constrained - * to these coordinates. - * - * @param anchor the coordinate space of this group - */ - public void setCoordinates(Rectangle2D anchor){ - EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); - - int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI); - int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI); - int x2 = (int)Math.round((anchor.getX() + anchor.getWidth())*MASTER_DPI/POINT_DPI); - int y2 = (int)Math.round((anchor.getY() + anchor.getHeight())*MASTER_DPI/POINT_DPI); - - spgr.setRectX1(x1); - spgr.setRectY1(y1); - spgr.setRectX2(x2); - spgr.setRectY2(y2); - - } - - /** - * Gets the coordinate space of this group. All children are constrained - * to these coordinates. - * - * @return the coordinate space of this group - */ - public Rectangle2D getCoordinates(){ - EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); - - Rectangle2D.Float anchor = new Rectangle2D.Float(); - anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI; - anchor.y = (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI; - anchor.width = (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI; - anchor.height = (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI; - - return anchor; - } - - /** - * Create a new ShapeGroup and create an instance of EscherSpgrContainer which represents a group of shapes - */ - protected EscherContainerRecord createSpContainer(boolean isChild) { - EscherContainerRecord spgr = new EscherContainerRecord(); - spgr.setRecordId(EscherContainerRecord.SPGR_CONTAINER); - spgr.setOptions((short)15); - - //The group itself is a shape, and always appears as the first EscherSpContainer in the group container. - EscherContainerRecord spcont = new EscherContainerRecord(); - spcont.setRecordId(EscherContainerRecord.SP_CONTAINER); - spcont.setOptions((short)15); - - EscherSpgrRecord spg = new EscherSpgrRecord(); - spg.setOptions((short)1); - spcont.addChildRecord(spg); - - EscherSpRecord sp = new EscherSpRecord(); - short type = (short)((ShapeType.NOT_PRIMITIVE.nativeId << 4) + 2); - sp.setOptions(type); - sp.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_GROUP); - spcont.addChildRecord(sp); - - EscherClientAnchorRecord anchor = new EscherClientAnchorRecord(); - spcont.addChildRecord(anchor); - - spgr.addChildRecord(spcont); - return spgr; - } - - /** - * Add a shape to this group. - * - * @param shape - the Shape to add - */ - public void addShape(HSLFShape shape){ - _escherContainer.addChildRecord(shape.getSpContainer()); - - HSLFSheet sheet = getSheet(); - shape.setSheet(sheet); - shape.setShapeId(sheet.allocateShapeId()); - shape.afterInsert(sheet); - } - - /** - * Moves this ShapeGroup to the specified location. - *

- * @param x the x coordinate of the top left corner of the shape in new location - * @param y the y coordinate of the top left corner of the shape in new location - */ - public void moveTo(int x, int y){ - java.awt.Rectangle anchor = getAnchor(); - int dx = x - anchor.x; - int dy = y - anchor.y; - anchor.translate(dx, dy); - setAnchor(anchor); - - HSLFShape[] shape = getShapes(); - for (int i = 0; i < shape.length; i++) { - java.awt.Rectangle chanchor = shape[i].getAnchor(); - chanchor.translate(dx, dy); - shape[i].setAnchor(chanchor); - } - } - - /** - * Returns the anchor (the bounding box rectangle) of this shape group. - * All coordinates are expressed in points (72 dpi). - * - * @return the anchor of this shape group - */ - public Rectangle2D getAnchor2D(){ - EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); - Rectangle2D.Float anchor = new Rectangle2D.Float(); - if(clientAnchor == null){ - logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord."); - EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID); - anchor = new Rectangle2D.Float( - (float)rec.getDx1()*POINT_DPI/MASTER_DPI, - (float)rec.getDy1()*POINT_DPI/MASTER_DPI, - (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI, - (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI - ); - } else { - anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI; - anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI; - anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ; - anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI; - } - - return anchor; - } - - /** - * Return type of the shape. - * In most cases shape group type is {@link org.apache.poi.hslf.model.ShapeTypes#NotPrimitive} - * - * @return type of the shape. - */ - public ShapeType getShapeType(){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int nativeId = spRecord.getOptions() >> 4; - return ShapeType.forId(nativeId, false); - } - - /** - * Returns null - shape groups can't have hyperlinks - * - * @return null. - */ - public Hyperlink getHyperlink(){ - return null; - } - - public void draw(Graphics2D graphics){ - - AffineTransform at = graphics.getTransform(); - - HSLFShape[] sh = getShapes(); - for (int i = 0; i < sh.length; i++) { - sh[i].draw(graphics); - } - - graphics.setTransform(at); - } - - @Override - public T getEscherChild(int recordId){ - EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0); - return groupInfoContainer.getChildById((short)recordId); - } - - public Iterator iterator() { - return getShapeList().iterator(); - } - - public boolean removeShape(HSLFShape shape) { - // TODO: implement! - throw new UnsupportedOperationException(); - } - - /** - * @return the shapes contained in this group container - */ - protected List getShapeList() { - // Out escher container record should contain several - // SpContainers, the first of which is the group shape itself - Iterator iter = _escherContainer.getChildIterator(); - - // Don't include the first SpContainer, it is always NotPrimitive - if (iter.hasNext()) { - iter.next(); - } - List shapeList = new ArrayList(); - while (iter.hasNext()) { - EscherRecord r = iter.next(); - if(r instanceof EscherContainerRecord) { - // Create the Shape for it - EscherContainerRecord container = (EscherContainerRecord)r; - HSLFShape shape = ShapeFactory.createShape(container, this); - shape.setSheet(getSheet()); - shapeList.add( shape ); - } else { - // Should we do anything special with these non - // Container records? - logger.log(POILogger.ERROR, "Shape contained non container escher record, was " + r.getClass().getName()); - } - } - - return shapeList; - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMasterSheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMasterSheet.java deleted file mode 100644 index 6c7574b8a7..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFMasterSheet.java +++ /dev/null @@ -1,57 +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.hslf.record.SheetContainer; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.sl.usermodel.MasterSheet; - -/** - * The superclass of all master sheets - Slide masters, Notes masters, etc. - * - * For now it's empty. When we understand more about masters in ppt we will add the common functionality here. - * - * @author Yegor Kozlov - */ -public abstract class HSLFMasterSheet extends HSLFSheet implements MasterSheet { - public HSLFMasterSheet(SheetContainer container, int sheetNo){ - super(container, sheetNo); - } - - /** - * Pickup a style attribute from the master. - * This is the "workhorse" which returns the default style attrubutes. - */ - public abstract TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) ; - - - /** - * Checks if the shape is a placeholder. - * (placeholders aren't normal shapes, they are visible only in the Edit Master mode) - * - * - * @return true if the shape is a placeholder - */ - public static boolean isPlaceholder(HSLFShape shape){ - if(!(shape instanceof HSLFTextShape)) return false; - - HSLFTextShape tx = (HSLFTextShape)shape; - return tx.getPlaceholderAtom() != null; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFNotes.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFNotes.java deleted file mode 100644 index 2a7698d21c..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFNotes.java +++ /dev/null @@ -1,75 +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 java.util.Arrays; -import java.util.List; - -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.Notes; - -/** - * This class represents a slide's notes in a PowerPoint Document. It - * allows access to the text within, and the layout. For now, it only - * does the text side of things though - * - * @author Nick Burch - */ - -public final class HSLFNotes extends HSLFSheet implements Notes { - private HSLFTextParagraph[] _runs; - - /** - * Constructs a Notes Sheet from the given Notes record. - * Initialises TextRuns, to provide easier access to the text - * - * @param notes the Notes record to read from - */ - public HSLFNotes(org.apache.poi.hslf.record.Notes notes) { - super(notes, notes.getNotesAtom().getSlideID()); - - // Now, build up TextRuns from pairs of TextHeaderAtom and - // one of TextBytesAtom or TextCharsAtom, found inside - // EscherTextboxWrapper's in the PPDrawing - _runs = findTextRuns(getPPDrawing()); - - // Set the sheet on each TextRun - for (HSLFTextParagraph tp : _runs) { - tp.supplySheet(this); - } - } - - /** - * Returns an array of all the TextRuns found - */ - public HSLFTextParagraph[] getTextRuns() { - return _runs; - } - - @Override - public List getTextParagraphs() { - return Arrays.asList(_runs); - } - - /** - * Return null - Notes Masters are not yet supported - */ - public HSLFMasterSheet getMasterSheet() { - return null; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFPictureShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFPictureShape.java deleted file mode 100644 index e6b72a60fb..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFPictureShape.java +++ /dev/null @@ -1,302 +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 java.awt.Graphics2D; -import java.awt.Insets; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.List; - -import javax.imageio.ImageIO; - -import org.apache.poi.ddf.EscherBSERecord; -import org.apache.poi.ddf.EscherComplexProperty; -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.EscherSpRecord; -import org.apache.poi.hslf.blip.Bitmap; -import org.apache.poi.hslf.record.Document; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.ShapeContainer; -import org.apache.poi.sl.usermodel.ShapeType; -import org.apache.poi.util.POILogger; -import org.apache.poi.util.StringUtil; -import org.apache.poi.util.Units; - - -/** - * Represents a picture in a PowerPoint document. - * - * @author Yegor Kozlov - */ -public class HSLFPictureShape extends HSLFSimpleShape { - - /** - * Windows Enhanced Metafile (EMF) - */ - public static final int EMF = 2; - - /** - * Windows Metafile (WMF) - */ - public static final int WMF = 3; - - /** - * Macintosh PICT - */ - public static final int PICT = 4; - - /** - * JPEG - */ - public static final int JPEG = 5; - - /** - * PNG - */ - public static final int PNG = 6; - - /** - * Windows DIB (BMP) - */ - public static final byte DIB = 7; - - /** - * Create a new Picture - * - * @param idx the index of the picture - */ - public HSLFPictureShape(int idx){ - this(idx, null); - } - - /** - * Create a new Picture - * - * @param idx the index of the picture - * @param parent the parent shape - */ - public HSLFPictureShape(int idx, ShapeContainer parent) { - super(null, parent); - _escherContainer = createSpContainer(idx, parent instanceof HSLFGroupShape); - } - - /** - * Create a Picture object - * - * @param escherRecord the EscherSpContainer record which holds information about - * this picture in the Slide - * @param parent the parent shape of this picture - */ - protected HSLFPictureShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - } - - /** - * Returns index associated with this picture. - * Index starts with 1 and points to a EscherBSE record which - * holds information about this picture. - * - * @return the index to this picture (1 based). - */ - public int getPictureIndex(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY); - return prop == null ? 0 : prop.getPropertyValue(); - } - - /** - * Create a new Picture and populate the inital structure of the EscherSp record which holds information about this picture. - - * @param idx the index of the picture which refers to EscherBSE container. - * @return the create Picture object - */ - protected EscherContainerRecord createSpContainer(int idx, boolean isChild) { - _escherContainer = super.createSpContainer(isChild); - _escherContainer.setOptions((short)15); - - EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); - spRecord.setOptions((short)((ShapeType.FRAME.nativeId << 4) | 0x2)); - - //set default properties for a picture - EscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x800080); - - //another weird feature of powerpoint: for picture id we must add 0x4000. - setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx); - - return _escherContainer; - } - - /** - * Resize this picture to the default size. - * For PNG and JPEG resizes the image to 100%, - * for other types sets the default size of 200x200 pixels. - */ - public void setDefaultSize(){ - HSLFPictureData pict = getPictureData(); - if (pict instanceof Bitmap){ - BufferedImage img = null; - try { - img = ImageIO.read(new ByteArrayInputStream(pict.getData())); - } - catch (IOException e){} - catch (NegativeArraySizeException ne) {} - - if(img != null) { - // Valid image, set anchor from it - setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*POINT_DPI/PIXEL_DPI, img.getHeight()*POINT_DPI/PIXEL_DPI)); - } else { - // Invalid image, go with the default metafile size - setAnchor(new java.awt.Rectangle(0, 0, 200, 200)); - } - } else { - //default size of a metafile picture is 200x200 - setAnchor(new java.awt.Rectangle(50, 50, 200, 200)); - } - } - - /** - * Returns the picture data for this picture. - * - * @return the picture data for this picture. - */ - public HSLFPictureData getPictureData(){ - HSLFSlideShow ppt = getSheet().getSlideShow(); - HSLFPictureData[] pict = ppt.getPictureData(); - - EscherBSERecord bse = getEscherBSERecord(); - if (bse == null){ - logger.log(POILogger.ERROR, "no reference to picture data found "); - } else { - for ( int i = 0; i < pict.length; i++ ) { - if (pict[i].getOffset() == bse.getOffset()){ - return pict[i]; - } - } - logger.log(POILogger.ERROR, "no picture found for our BSE offset " + bse.getOffset()); - } - return null; - } - - protected EscherBSERecord getEscherBSERecord(){ - HSLFSlideShow ppt = getSheet().getSlideShow(); - Document doc = ppt.getDocumentRecord(); - EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); - EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); - if(bstore == null) { - logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found "); - return null; - } - List lst = bstore.getChildRecords(); - int idx = getPictureIndex(); - if (idx == 0){ - logger.log(POILogger.DEBUG, "picture index was not found, returning "); - return null; - } - return (EscherBSERecord)lst.get(idx-1); - } - - /** - * Name of this picture. - * - * @return name of this picture - */ - public String getPictureName(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherComplexProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME); - if (prop == null) return null; - String name = StringUtil.getFromUnicodeLE(prop.getComplexData()); - return name.trim(); - } - - /** - * Name of this picture. - * - * @param name of this picture - */ - public void setPictureName(String name){ - EscherOptRecord opt = getEscherOptRecord(); - byte[] data = StringUtil.getToUnicodeLE(name + '\u0000'); - EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.BLIP__BLIPFILENAME, false, data); - opt.addEscherProperty(prop); - } - - /** - * By default set the orininal image size - */ - protected void afterInsert(HSLFSheet sh){ - super.afterInsert(sh); - - EscherBSERecord bse = getEscherBSERecord(); - bse.setRef(bse.getRef() + 1); - - java.awt.Rectangle anchor = getAnchor(); - if (anchor.equals(new java.awt.Rectangle())){ - setDefaultSize(); - } - } - - public void draw(Graphics2D graphics){ - AffineTransform at = graphics.getTransform(); - ShapePainter.paint(this, graphics); - - HSLFPictureData data = getPictureData(); - if(data != null) data.draw(graphics, this); - - graphics.setTransform(at); - } - - /** - * Returns the clipping values as percent ratio relatively to the image size. - * The anchor specified by {@link #getLogicalAnchor2D()} is the displayed size, - * i.e. the size of the already clipped image - * - * @return the clipping as insets converted/scaled to 100000 (=100%) - */ - public Insets getBlipClip() { - EscherOptRecord opt = getEscherOptRecord(); - - double top = getFractProp(opt, EscherProperties.BLIP__CROPFROMTOP); - double bottom = getFractProp(opt, EscherProperties.BLIP__CROPFROMBOTTOM); - double left = getFractProp(opt, EscherProperties.BLIP__CROPFROMLEFT); - double right = getFractProp(opt, EscherProperties.BLIP__CROPFROMRIGHT); - - // if all crop values are zero (the default) then no crop rectangle is set, return null - return (top==0 && bottom==0 && left==0 && right==0) - ? null - : new Insets((int)(top*100000), (int)(left*100000), (int)(bottom*100000), (int)(right*100000)); - } - - /** - * @return the fractional property or 0 if not defined - */ - private static double getFractProp(EscherOptRecord opt, short propertyId) { - EscherSimpleProperty prop = getEscherProperty(opt, propertyId); - if (prop == null) return 0; - int fixedPoint = prop.getPropertyValue(); - return Units.fixedPointToDouble(fixedPoint); - } -} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFShape.java deleted file mode 100644 index 4e2229982e..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFShape.java +++ /dev/null @@ -1,526 +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 java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.Rectangle2D; -import java.util.Iterator; - -import org.apache.poi.ddf.*; -import org.apache.poi.hslf.record.ColorSchemeAtom; -import org.apache.poi.sl.usermodel.*; -import org.apache.poi.util.*; - -/** - *

- * Represents a Shape which is the elemental object that composes a drawing. - * This class is a wrapper around EscherSpContainer which holds all information - * about a shape in PowerPoint document. - *

- *

- * When you add a shape, you usually specify the dimensions of the shape and the position - * of the upper'left corner of the bounding box for the shape relative to the upper'left - * corner of the page, worksheet, or slide. Distances in the drawing layer are measured - * in points (72 points = 1 inch). - *

- *

- * - * @author Yegor Kozlov - */ -public abstract class HSLFShape implements Shape { - - // For logging - protected POILogger logger = POILogFactory.getLogger(this.getClass()); - - /** - * In Escher absolute distances are specified in - * English Metric Units (EMUs), occasionally referred to as A units; - * there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point. - */ - public static final int EMU_PER_INCH = 914400; - public static final int EMU_PER_POINT = 12700; - public static final int EMU_PER_CENTIMETER = 360000; - - /** - * Master DPI (576 pixels per inch). - * Used by the reference coordinate system in PowerPoint. - */ - public static final int MASTER_DPI = 576; - - /** - * Pixels DPI (96 pixels per inch) - */ - public static final int PIXEL_DPI = 96; - - /** - * Points DPI (72 pixels per inch) - */ - public static final int POINT_DPI = 72; - - /** - * Either EscherSpContainer or EscheSpgrContainer record - * which holds information about this shape. - */ - protected EscherContainerRecord _escherContainer; - - /** - * Parent of this shape. - * null for the topmost shapes. - */ - protected ShapeContainer _parent; - - /** - * The Sheet this shape belongs to - */ - protected HSLFSheet _sheet; - - /** - * Fill - */ - protected HSLFFill _fill; - - /** - * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of this Shape - */ - protected HSLFShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - _escherContainer = escherRecord; - _parent = parent; - } - - /** - * Creates the lowerlevel escher records for this shape. - */ - protected abstract EscherContainerRecord createSpContainer(boolean isChild); - - /** - * @return the parent of this shape - */ - public ShapeContainer getParent(){ - return _parent; - } - - /** - * @return name of the shape. - */ - public String getShapeName(){ - 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 ); - spRecord.setVersion( (short) 0x2 ); - } - - /** - * Returns the anchor (the bounding box rectangle) of this shape. - * All coordinates are expressed in points (72 dpi). - * - * @return the anchor of this shape - */ - public java.awt.Rectangle getAnchor(){ - Rectangle2D anchor2d = getAnchor2D(); - return anchor2d.getBounds(); - } - - /** - * Returns the anchor (the bounding box rectangle) of this shape. - * All coordinates are expressed in points (72 dpi). - * - * @return the anchor of this shape - */ - public Rectangle2D getAnchor2D(){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int flags = spRecord.getFlags(); - Rectangle2D anchor=null; - if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ - EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID); - anchor = new java.awt.Rectangle(); - if(rec == null){ - logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found"); - EscherClientAnchorRecord clrec = getEscherChild(EscherClientAnchorRecord.RECORD_ID); - anchor = new java.awt.Rectangle(); - anchor = new Rectangle2D.Float( - (float)clrec.getCol1()*POINT_DPI/MASTER_DPI, - (float)clrec.getFlag()*POINT_DPI/MASTER_DPI, - (float)(clrec.getDx1()-clrec.getCol1())*POINT_DPI/MASTER_DPI, - (float)(clrec.getRow1()-clrec.getFlag())*POINT_DPI/MASTER_DPI - ); - } else { - anchor = new Rectangle2D.Float( - (float)rec.getDx1()*POINT_DPI/MASTER_DPI, - (float)rec.getDy1()*POINT_DPI/MASTER_DPI, - (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI, - (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI - ); - } - } - else { - EscherClientAnchorRecord rec = getEscherChild(EscherClientAnchorRecord.RECORD_ID); - anchor = new java.awt.Rectangle(); - anchor = new Rectangle2D.Float( - (float)rec.getCol1()*POINT_DPI/MASTER_DPI, - (float)rec.getFlag()*POINT_DPI/MASTER_DPI, - (float)(rec.getDx1()-rec.getCol1())*POINT_DPI/MASTER_DPI, - (float)(rec.getRow1()-rec.getFlag())*POINT_DPI/MASTER_DPI - ); - } - return anchor; - } - - public Rectangle2D getLogicalAnchor2D(){ - return getAnchor2D(); - } - - /** - * Sets the anchor (the bounding box rectangle) of this shape. - * All coordinates should be expressed in points (72 dpi). - * - * @param anchor new anchor - */ - public void setAnchor(Rectangle2D anchor){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int flags = spRecord.getFlags(); - if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ - EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(EscherChildAnchorRecord.RECORD_ID); - rec.setDx1((int)(anchor.getX()*MASTER_DPI/POINT_DPI)); - rec.setDy1((int)(anchor.getY()*MASTER_DPI/POINT_DPI)); - rec.setDx2((int)((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI)); - rec.setDy2((int)((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI)); - } - else { - EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(EscherClientAnchorRecord.RECORD_ID); - rec.setFlag((short)(anchor.getY()*MASTER_DPI/POINT_DPI)); - rec.setCol1((short)(anchor.getX()*MASTER_DPI/POINT_DPI)); - rec.setDx1((short)(((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI))); - rec.setRow1((short)(((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI))); - } - - } - - /** - * Moves the top left corner of the shape to the specified point. - * - * @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){ - Rectangle2D anchor = getAnchor2D(); - anchor.setRect(x, y, anchor.getWidth(), anchor.getHeight()); - setAnchor(anchor); - } - - /** - * Helper method to return escher child by record ID - * - * @return escher record or null if not found. - */ - public static T getEscherChild(EscherContainerRecord owner, int recordId){ - return owner.getChildById((short)recordId); - } - - public T getEscherChild(int recordId){ - return _escherContainer.getChildById((short)recordId); - } - - /** - * Returns escher property by id. - * - * @return escher property or null if not found. - */ - public static T getEscherProperty(EscherOptRecord opt, int propId){ - return opt.lookup(propId); - } - - /** - * Set an escher property for this shape. - * - * @param opt The opt record to set the properties to. - * @param propId The id of the property. One of the constants defined in EscherOptRecord. - * @param value value of the property. If value = -1 then the property is removed. - */ - public static void setEscherProperty(EscherOptRecord opt, short propId, int value){ - java.util.List props = opt.getEscherProperties(); - for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) { - if (iterator.next().getPropertyNumber() == propId){ - iterator.remove(); - break; - } - } - if (value != -1) { - opt.addEscherProperty(new EscherSimpleProperty(propId, value)); - opt.sortProperties(); - } - } - - /** - * Set an simple escher property for this shape. - * - * @param propId The id of the property. One of the constants defined in EscherOptRecord. - * @param value value of the property. If value = -1 then the property is removed. - */ - public void setEscherProperty(short propId, int value){ - EscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, propId, value); - } - - /** - * Get the value of a simple escher property for this shape. - * - * @param propId The id of the property. One of the constants defined in EscherOptRecord. - */ - public int getEscherProperty(short propId){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, propId); - return prop == null ? 0 : prop.getPropertyValue(); - } - - /** - * Get the value of a simple escher property for this shape. - * - * @param propId The id of the property. One of the constants defined in EscherOptRecord. - */ - public int getEscherProperty(short propId, int defaultValue){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, propId); - return prop == null ? defaultValue : prop.getPropertyValue(); - } - - /** - * @return The shape container and it's children that can represent this - * shape. - */ - public EscherContainerRecord getSpContainer(){ - return _escherContainer; - } - - /** - * Event which fires when a shape is inserted in the sheet. - * In some cases we need to propagate changes to upper level containers. - *
- * Default implementation does nothing. - * - * @param sh - owning shape - */ - protected void afterInsert(HSLFSheet sh){ - if(_fill != null) { - _fill.afterInsert(sh); - } - } - - /** - * @return the SlideShow this shape belongs to - */ - public HSLFSheet getSheet(){ - return _sheet; - } - - /** - * Assign the SlideShow this shape belongs to - * - * @param sheet owner of this shape - */ - public void setSheet(HSLFSheet sheet){ - _sheet = sheet; - } - - Color getColor(short colorProperty, short opacityProperty, int defaultColor){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty p = getEscherProperty(opt, colorProperty); - if(p == null && defaultColor == -1) return null; - - int val = (p == null) ? defaultColor : p.getPropertyValue(); - - EscherColorRef ecr = new EscherColorRef(val); - - boolean fPaletteIndex = ecr.hasPaletteIndexFlag(); - boolean fPaletteRGB = ecr.hasPaletteRGBFlag(); - boolean fSystemRGB = ecr.hasSystemRGBFlag(); - boolean fSchemeIndex = ecr.hasSchemeIndexFlag(); - boolean fSysIndex = ecr.hasSysIndexFlag(); - - int rgb[] = ecr.getRGB(); - - HSLFSheet sheet = getSheet(); - if (fSchemeIndex && sheet != null) { - //red is the index to the color scheme - ColorSchemeAtom ca = sheet.getColorScheme(); - int schemeColor = ca.getColor(ecr.getSchemeIndex()); - - rgb[0] = (schemeColor >> 0) & 0xFF; - rgb[1] = (schemeColor >> 8) & 0xFF; - rgb[2] = (schemeColor >> 16) & 0xFF; - } else if (fPaletteIndex){ - //TODO - } else if (fPaletteRGB){ - //TODO - } else if (fSystemRGB){ - //TODO - } else if (fSysIndex){ - //TODO - } - - double alpha = getAlpha(opacityProperty); - return new Color(rgb[0], rgb[1], rgb[2], (int)(alpha*255.0)); - } - - double getAlpha(short opacityProperty) { - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty op = getEscherProperty(opt, opacityProperty); - int defaultOpacity = 0x00010000; - int opacity = (op == null) ? defaultOpacity : op.getPropertyValue(); - return Units.fixedPointToDouble(opacity); - } - - Color toRGB(int val){ - int a = (val >> 24) & 0xFF; - int b = (val >> 16) & 0xFF; - int g = (val >> 8) & 0xFF; - int r = (val >> 0) & 0xFF; - - if(a == 0xFE){ - // Color is an sRGB value specified by red, green, and blue fields. - } else if (a == 0xFF){ - // Color is undefined. - } else { - // index in the color scheme - ColorSchemeAtom ca = getSheet().getColorScheme(); - int schemeColor = ca.getColor(a); - - r = (schemeColor >> 0) & 0xFF; - g = (schemeColor >> 8) & 0xFF; - b = (schemeColor >> 16) & 0xFF; - } - return new Color(r, g, b); - } - - /** - * @return id for the shape. - */ - public int getShapeId(){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - return spRecord == null ? 0 : spRecord.getShapeId(); - } - - /** - * Sets shape ID - * - * @param id of the shape - */ - public void setShapeId(int id){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - if(spRecord != null) spRecord.setShapeId(id); - } - - /** - * Fill properties of this shape - * - * @return fill properties of this shape - */ - public HSLFFill getFill(){ - if(_fill == null) { - _fill = new HSLFFill(this); - } - return _fill; - } - - public FillStyle getFillStyle() { - return getFill().getFillStyle(); - } - - /** - * Returns the hyperlink assigned to this shape - * - * @return the hyperlink assigned to this shape - * or null if not found. - */ - public Hyperlink getHyperlink(){ - return Hyperlink.find(this); - } - - public void draw(Graphics2D graphics){ - logger.log(POILogger.INFO, "Rendering " + getShapeName()); - } - - /** - * Return shape outline as a java.awt.Shape object - * - * @return the shape outline - */ - public java.awt.Shape getOutline(){ - return getLogicalAnchor2D(); - } - - public EscherOptRecord getEscherOptRecord() { - return getEscherChild(EscherOptRecord.RECORD_ID); - } - - public boolean getFlipHorizontal(){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0; - } - - public void setFlipHorizontal(boolean flip) { - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int flag = spRecord.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ; - spRecord.setFlags(flag); - } - - public boolean getFlipVertical(){ - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0; - } - - public void setFlipVertical(boolean flip) { - EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int flag = spRecord.getFlags() | EscherSpRecord.FLAG_FLIPVERT; - spRecord.setFlags(flag); - } - - public double getRotation(){ - int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION); - double angle = Units.fixedPointToDouble(rot) % 360.0; - return angle; - } - - public void setRotation(double theta){ - int rot = Units.doubleToFixedPoint(theta % 360.0); - setEscherProperty(EscherProperties.TRANSFORM__ROTATION, rot); - } - - public boolean isPlaceholder() { - return false; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSheet.java deleted file mode 100644 index 5156f37b60..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSheet.java +++ /dev/null @@ -1,530 +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 java.awt.Graphics2D; -import java.util.*; - -import org.apache.poi.ddf.*; -import org.apache.poi.hslf.record.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.Sheet; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * This class defines the common format of "Sheets" in a powerpoint - * document. Such sheets could be Slides, Notes, Master etc - * - * @author Nick Burch - * @author Yegor Kozlov - */ - -public abstract class HSLFSheet implements Sheet { - private static POILogger logger = POILogFactory.getLogger(HSLFSheet.class); - - /** - * The SlideShow we belong to - */ - private HSLFSlideShow _slideShow; - - /** - * Sheet background - */ - private HSLFBackground _background; - - /** - * Record container that holds sheet data. - * For slides it is org.apache.poi.hslf.record.Slide, - * for notes it is org.apache.poi.hslf.record.Notes, - * for slide masters it is org.apache.poi.hslf.record.SlideMaster, etc. - */ - private SheetContainer _container; - - private int _sheetNo; - - public HSLFSheet(SheetContainer container, int sheetNo) { - _container = container; - _sheetNo = sheetNo; - } - - /** - * Returns an array of all the TextRuns in the sheet. - */ - public abstract HSLFTextParagraph[] getTextRuns(); - - /** - * Returns the (internal, RefID based) sheet number, as used - * to in PersistPtr stuff. - */ - public int _getSheetRefId() { - return _container.getSheetId(); - } - - /** - * Returns the (internal, SlideIdentifier based) sheet number, as used - * to reference this sheet from other records. - */ - public int _getSheetNumber() { - return _sheetNo; - } - - /** - * Fetch the PPDrawing from the underlying record - */ - protected PPDrawing getPPDrawing() { - return _container.getPPDrawing(); - } - - /** - * Fetch the SlideShow we're attached to - */ - public HSLFSlideShow getSlideShow() { - return _slideShow; - } - - /** - * Return record container for this sheet - */ - public SheetContainer getSheetContainer() { - return _container; - } - - /** - * Set the SlideShow we're attached to. - * Also passes it on to our child RichTextRuns - */ - public void setSlideShow(HSLFSlideShow ss) { - _slideShow = ss; - HSLFTextParagraph[] trs = getTextRuns(); - if (trs == null) return; - for (HSLFTextParagraph tp : trs) { - tp.supplySheet(this); - } - } - - - /** - * For a given PPDrawing, grab all the TextRuns - */ - public static HSLFTextParagraph[] findTextRuns(PPDrawing ppdrawing) { - final List runsV = new ArrayList(); - final EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers(); - for (int i = 0; i < wrappers.length; i++) { - int s1 = runsV.size(); - - // propagate parents to parent-aware records - RecordContainer.handleParentAwareRecords(wrappers[i]); - findTextRuns(wrappers[i], runsV); - int s2 = runsV.size(); - if (s2 != s1){ - HSLFTextParagraph t = runsV.get(runsV.size()-1); - t.setShapeId(wrappers[i].getShapeId()); - } - } - return runsV.toArray(new HSLFTextParagraph[runsV.size()]); - } - /** - * Scans through the supplied record array, looking for - * a TextHeaderAtom followed by one of a TextBytesAtom or - * a TextCharsAtom. Builds up TextRuns from these - * - * @param records the records to build from - * @param found vector to add any found to - */ - protected static void findTextParagraphs(final Record[] records, final List found) { - findTextRuns(records, found, null); - } - /** - * Scans through the supplied record array, looking for - * a TextHeaderAtom followed by one of a TextBytesAtom or - * a TextCharsAtom. Builds up TextRuns from these - * - * @param wrapper an EscherTextboxWrapper - * @param found vector to add any found to - */ - protected static void findTextRuns(final EscherTextboxWrapper wrapper, final List found) { - findTextRuns(wrapper.getChildRecords(), found, wrapper.getStyleTextProp9Atom()); - } - /** - * Scans through the supplied record array, looking for - * a TextHeaderAtom followed by one of a TextBytesAtom or - * a TextCharsAtom. Builds up TextRuns from these - * - * @param records the records to build from - * @param found vector to add any found to - * @param styleTextProp9Atom a StyleTextProp9Atom with numbered lists info - */ - protected static void findTextRuns(final Record[] records, final List found, final StyleTextProp9Atom styleTextProp9Atom) { - for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) { - if (records[i] instanceof TextHeaderAtom) { - TextHeaderAtom tha = (TextHeaderAtom) records[i]; - StyleTextPropAtom stpa = null; - HSLFTextParagraph trun = null; - Record next = null; - Record subs = null; - - // See what follows the TextHeaderAtom - next = records[i+1]; - if (i < records.length - 2) { - subs = records[i+2]; - } - - // Is the next record one we need to skip over? - if (subs != null) { - if (next instanceof TextRulerAtom || - next instanceof MasterTextPropAtom || - next instanceof TextSpecInfoAtom) { - // Ignore this one, check the one after - next = subs; - if (i < records.length - 3) { - subs = records[i+3]; - } else { - subs = null; - } - } - } - - // Is the subsequent record a style one? - if (subs != null && subs instanceof StyleTextPropAtom) { - stpa = (StyleTextPropAtom)subs; - } - - // Now, check if the next record is one to record - if (next instanceof TextCharsAtom) { - TextCharsAtom tca = (TextCharsAtom)next; - trun = new HSLFTextParagraph(tha, tca, stpa); - } else if (next instanceof TextBytesAtom) { - TextBytesAtom tba = (TextBytesAtom)next; - trun = new HSLFTextParagraph(tha, tba, stpa); - } else if (next instanceof StyleTextPropAtom) { - stpa = (StyleTextPropAtom)next; - } else if (next instanceof TextHeaderAtom) { - // Seems to be a mostly, but not completely deleted block of - // text. Only the header remains, which isn't useful alone - // Skip on to the next TextHeaderAtom - continue; - } else { - logger.log(POILogger.ERROR, "Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + next.getRecordType()); - } - - if (trun != null) { - List lst = new ArrayList(); - for (int j = i; j < records.length; j++) { - if(j > i && records[j] instanceof TextHeaderAtom) break; - lst.add(records[j]); - } - Record[] recs = new Record[lst.size()]; - lst.toArray(recs); - trun._records = recs; - trun.setIndex(slwtIndex); - trun.setStyleTextProp9Atom(styleTextProp9Atom); - found.add(trun); - i++; - } else { - // Not a valid one, so skip on to next and look again - } - slwtIndex++; - } - } - } - - /** - * Returns all shapes contained in this Sheet - * - * @return all shapes contained in this Sheet (Slide or Notes) - */ - public HSLFShape[] getShapes() { - List shapeList = getShapeList(); - return shapeList.toArray(new HSLFShape[shapeList.size()]); - } - - /** - * Add a new Shape to this Slide - * - * @param shape - the Shape to add - */ - public void addShape(HSLFShape shape) { - PPDrawing ppdrawing = getPPDrawing(); - - EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; - EscherContainerRecord spgr = (EscherContainerRecord) HSLFShape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER); - spgr.addChildRecord(shape.getSpContainer()); - - shape.setSheet(this); - shape.setShapeId(allocateShapeId()); - shape.afterInsert(this); - } - - /** - * Allocates new shape id for the new drawing group id. - * - * @return a new shape id. - */ - public int allocateShapeId() - { - EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); - EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord(); - - dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 ); - - // Add to existing cluster if space available - for (int i = 0; i < dgg.getFileIdClusters().length; i++) - { - EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i]; - if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024) - { - int result = c.getNumShapeIdsUsed() + (1024 * (i+1)); - c.incrementShapeId(); - dg.setNumShapes( dg.getNumShapes() + 1 ); - dg.setLastMSOSPID( result ); - if (result >= dgg.getShapeIdMax()) - dgg.setShapeIdMax( result + 1 ); - return result; - } - } - - // Create new cluster - dgg.addCluster( dg.getDrawingGroupId(), 0, false ); - dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId(); - dg.setNumShapes( dg.getNumShapes() + 1 ); - int result = (1024 * dgg.getFileIdClusters().length); - dg.setLastMSOSPID( result ); - if (result >= dgg.getShapeIdMax()) - dgg.setShapeIdMax( result + 1 ); - return result; - } - - /** - * Removes the specified shape from this sheet. - * - * @param shape shape to be removed from this sheet, if present. - * @return true if the shape was deleted. - */ - public boolean removeShape(HSLFShape shape) { - PPDrawing ppdrawing = getPPDrawing(); - - EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; - EscherContainerRecord spgr = null; - - for (Iterator it = dg.getChildIterator(); it.hasNext();) { - EscherRecord rec = it.next(); - if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) { - spgr = (EscherContainerRecord) rec; - break; - } - } - if(spgr == null) { - return false; - } - - List lst = spgr.getChildRecords(); - boolean result = lst.remove(shape.getSpContainer()); - spgr.setChildRecords(lst); - return result; - } - - /** - * Called by SlideShow ater a new sheet is created - */ - public void onCreate(){ - - } - - /** - * Return the master sheet . - */ - public abstract HSLFMasterSheet getMasterSheet(); - - /** - * Color scheme for this sheet. - */ - public ColorSchemeAtom getColorScheme() { - return _container.getColorScheme(); - } - - /** - * Returns the background shape for this sheet. - * - * @return the background shape for this sheet. - */ - public HSLFBackground getBackground() { - if (_background == null) { - PPDrawing ppdrawing = getPPDrawing(); - - EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; - EscherContainerRecord spContainer = null; - - for (Iterator it = dg.getChildIterator(); it.hasNext();) { - EscherRecord rec = it.next(); - if (rec.getRecordId() == EscherContainerRecord.SP_CONTAINER) { - spContainer = (EscherContainerRecord) rec; - break; - } - } - _background = new HSLFBackground(spContainer, null); - _background.setSheet(this); - } - return _background; - } - - public void draw(Graphics2D graphics){ - - } - - /** - * Subclasses should call this method and update the array of text runs - * when a text shape is added - * - * @param shape - */ - protected void onAddTextShape(HSLFTextShape shape) { - - } - - /** - * Return placeholder by text type - * - * @param type type of text, See {@link org.apache.poi.hslf.record.TextHeaderAtom} - * @return TextShape or null - */ - public HSLFTextShape getPlaceholderByTextType(int type){ - HSLFShape[] shape = getShapes(); - for (int i = 0; i < shape.length; i++) { - if(shape[i] instanceof HSLFTextShape){ - HSLFTextShape tx = (HSLFTextShape)shape[i]; - HSLFTextParagraph run = tx.getTextParagraph(); - if(run != null && run.getRunType() == type){ - return tx; - } - } - } - return null; - } - - /** - * Search text placeholer by its type - * - * @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom} - * @return TextShape or null - */ - public HSLFTextShape getPlaceholder(int type){ - HSLFShape[] shape = getShapes(); - for (int i = 0; i < shape.length; i++) { - if(shape[i] instanceof HSLFTextShape){ - HSLFTextShape tx = (HSLFTextShape)shape[i]; - int placeholderId = 0; - OEPlaceholderAtom oep = tx.getPlaceholderAtom(); - if(oep != null) { - placeholderId = oep.getPlaceholderId(); - } else { - //special case for files saved in Office 2007 - RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID); - if(hldr != null) placeholderId = hldr.getPlaceholderId(); - } - if(placeholderId == type){ - return tx; - } - } - } - return null; - } - - /** - * Return programmable tag associated with this sheet, e.g. ___PPT12. - * - * @return programmable tag associated with this sheet. - */ - public String getProgrammableTag(){ - String tag = null; - RecordContainer progTags = (RecordContainer) - getSheetContainer().findFirstOfType( - RecordTypes.ProgTags.typeID - ); - if(progTags != null) { - RecordContainer progBinaryTag = (RecordContainer) - progTags.findFirstOfType( - RecordTypes.ProgBinaryTag.typeID - ); - if(progBinaryTag != null) { - CString binaryTag = (CString) - progBinaryTag.findFirstOfType( - RecordTypes.CString.typeID - ); - if(binaryTag != null) tag = binaryTag.getText(); - } - } - - return tag; - - } - - public Iterator iterator() { - return getShapeList().iterator(); - } - - - /** - * Returns all shapes contained in this Sheet - * - * @return all shapes contained in this Sheet (Slide or Notes) - */ - protected List getShapeList() { - PPDrawing ppdrawing = getPPDrawing(); - - EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; - EscherContainerRecord spgr = null; - - for (Iterator it = dg.getChildIterator(); it.hasNext();) { - EscherRecord rec = it.next(); - if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) { - spgr = (EscherContainerRecord) rec; - break; - } - } - if (spgr == null) { - throw new IllegalStateException("spgr not found"); - } - - List shapeList = new ArrayList(); - Iterator it = spgr.getChildIterator(); - if (it.hasNext()) { - // skip first item - it.next(); - } - for (; it.hasNext();) { - EscherContainerRecord sp = (EscherContainerRecord) it.next(); - HSLFShape sh = ShapeFactory.createShape(sp, null); - sh.setSheet(this); - shapeList.add(sh); - } - - return shapeList; - } - - /** - * @return whether shapes on the master sheet should be shown. By default master graphics is turned off. - * Sheets that support the notion of master (slide, slideLayout) should override it and - * check this setting - */ - public boolean getFollowMasterGraphics() { - return false; - } - - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSimpleShape.java deleted file mode 100644 index 71c3c34d77..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSimpleShape.java +++ /dev/null @@ -1,420 +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 java.awt.Color; -import java.awt.Graphics2D; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.io.ByteArrayOutputStream; -import java.util.ArrayList; - -import org.apache.poi.ddf.DefaultEscherRecordFactory; -import org.apache.poi.ddf.EscherChildAnchorRecord; -import org.apache.poi.ddf.EscherClientAnchorRecord; -import org.apache.poi.ddf.EscherClientDataRecord; -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.EscherSpRecord; -import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.hslf.record.InteractiveInfo; -import org.apache.poi.hslf.record.InteractiveInfoAtom; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.sl.usermodel.*; -import org.apache.poi.sl.usermodel.StrokeStyle.*; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.Units; - -/** - * An abstract simple (non-group) shape. - * This is the parent class for all primitive shapes like Line, Rectangle, etc. - * - * @author Yegor Kozlov - */ -public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape { - - public final static double DEFAULT_LINE_WIDTH = 0.75; - - /** - * Records stored in EscherClientDataRecord - */ - protected Record[] _clientRecords; - protected EscherClientDataRecord _clientData; - - /** - * Create a SimpleShape object and initialize it from the supplied Record container. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of the shape - */ - protected HSLFSimpleShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - } - - /** - * Create a new Shape - * - * @param isChild true if the Line is inside a group, false otherwise - * @return the record container which holds this shape - */ - protected EscherContainerRecord createSpContainer(boolean isChild) { - _escherContainer = new EscherContainerRecord(); - _escherContainer.setRecordId( EscherContainerRecord.SP_CONTAINER ); - _escherContainer.setOptions((short)15); - - EscherSpRecord sp = new EscherSpRecord(); - int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE; - if (isChild) flags |= EscherSpRecord.FLAG_CHILD; - sp.setFlags(flags); - _escherContainer.addChildRecord(sp); - - EscherOptRecord opt = new EscherOptRecord(); - opt.setRecordId(EscherOptRecord.RECORD_ID); - _escherContainer.addChildRecord(opt); - - EscherRecord anchor; - if(isChild) anchor = new EscherChildAnchorRecord(); - else { - anchor = new EscherClientAnchorRecord(); - - //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); - anchor.fillFields(header, 0, null); - } - _escherContainer.addChildRecord(anchor); - - return _escherContainer; - } - - /** - * Returns width of the line in in points - */ - public double getLineWidth(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH); - double width = (prop == null) ? DEFAULT_LINE_WIDTH : Units.toPoints(prop.getPropertyValue()); - return width; - } - - /** - * Sets the width of line in in points - * @param width the width of line in in points - */ - public void setLineWidth(double width){ - EscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH, Units.toEMU(width)); - } - - /** - * Sets the color of line - * - * @param color new color of the line - */ - public void setLineColor(Color color){ - EscherOptRecord opt = getEscherOptRecord(); - if (color == null) { - setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000); - } else { - int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); - setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, rgb); - setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, color == null ? 0x180010 : 0x180018); - } - } - - /** - * @return color of the line. If color is not set returns java.awt.Color.black - */ - public Color getLineColor(){ - EscherOptRecord opt = getEscherOptRecord(); - - EscherSimpleProperty p = getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH); - if(p != null && (p.getPropertyValue() & 0x8) == 0) return null; - - Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1); - return clr == null ? Color.black : clr; - } - - /** - * Gets line dashing. - * - * @return dashing of the line. - */ - public LineDash getLineDashing(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING); - return (prop == null) ? LineDash.SOLID : LineDash.fromNativeId(prop.getPropertyValue()); - } - - /** - * Sets line dashing. - * - * @param pen new style of the line. - */ - public void setLineDashing(LineDash pen){ - EscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING, pen == LineDash.SOLID ? -1 : pen.nativeId); - } - - /** - * Gets the line compound style - * - * @return the compound style of the line. - */ - public LineCompound getLineCompound() { - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE); - return (prop == null) ? LineCompound.SINGLE : LineCompound.fromNativeId(prop.getPropertyValue()); - } - - /** - * Sets the line compound style - * - * @param style new compound style of the line. - */ - public void setLineCompound(LineCompound style){ - EscherOptRecord opt = getEscherOptRecord(); - setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE, style == LineCompound.SINGLE ? -1 : style.nativeId); - } - - /** - * Returns line style. One of the constants defined in this class. - * - * @return style of the line. - */ - public StrokeStyle getStrokeStyle(){ - return new StrokeStyle() { - public PaintStyle getPaint() { - return null; - } - - public LineCap getLineCap() { - return null; - } - - public LineDash getLineDash() { - return null; - } - - public LineCompound getLineCompound() { - return null; - } - - public double getLineWidth() { - return 0; - } - - }; - } - - /** - * The color used to fill this shape. - */ - public Color getFillColor(){ - return getFill().getForegroundColor(); - } - - /** - * The color used to fill this shape. - * - * @param color the background color - */ - public void setFillColor(Color color){ - getFill().setForegroundColor(color); - } - - /** - * - * @return 'absolute' anchor of this shape relative to the parent sheet - */ - public Rectangle2D getLogicalAnchor2D(){ - Rectangle2D anchor = getAnchor2D(); - - //if it is a groupped shape see if we need to transform the coordinates - if (getParent() != null){ - ArrayList lst = new ArrayList(); - for (ShapeContainer parent=this.getParent(); - parent instanceof HSLFGroupShape; - parent = ((HSLFGroupShape)parent).getParent()) { - lst.add(0, (HSLFGroupShape)parent); - } - - AffineTransform tx = new AffineTransform(); - for(HSLFGroupShape prnt : lst) { - Rectangle2D exterior = prnt.getAnchor2D(); - Rectangle2D interior = prnt.getCoordinates(); - - double scaleX = exterior.getWidth() / interior.getWidth(); - double scaleY = exterior.getHeight() / interior.getHeight(); - - tx.translate(exterior.getX(), exterior.getY()); - tx.scale(scaleX, scaleY); - tx.translate(-interior.getX(), -interior.getY()); - - } - anchor = tx.createTransformedShape(anchor).getBounds2D(); - } - - double angle = getRotation(); - if(angle != 0.){ - double centerX = anchor.getX() + anchor.getWidth()/2; - double centerY = anchor.getY() + anchor.getHeight()/2; - - AffineTransform trans = new AffineTransform(); - trans.translate(centerX, centerY); - trans.rotate(Math.toRadians(angle)); - trans.translate(-centerX, -centerY); - - Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D(); - if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) || - (anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){ - trans = new AffineTransform(); - trans.translate(centerX, centerY); - trans.rotate(Math.PI/2); - trans.translate(-centerX, -centerY); - anchor = trans.createTransformedShape(anchor).getBounds2D(); - } - } - return anchor; - } - - public void draw(Graphics2D graphics){ - AffineTransform at = graphics.getTransform(); - ShapePainter.paint(this, graphics); - graphics.setTransform(at); - } - - /** - * Find a record in the underlying EscherClientDataRecord - * - * @param recordType type of the record to search - */ - @SuppressWarnings("unchecked") - protected T getClientDataRecord(int recordType) { - - Record[] records = getClientRecords(); - if(records != null) for (int i = 0; i < records.length; i++) { - if(records[i].getRecordType() == recordType){ - return (T)records[i]; - } - } - return null; - } - - /** - * Search for EscherClientDataRecord, if found, convert its contents into an array of HSLF records - * - * @return an array of HSLF records contained in the shape's EscherClientDataRecord or null - */ - protected Record[] getClientRecords() { - if(_clientData == null){ - EscherRecord r = getEscherChild(EscherClientDataRecord.RECORD_ID); - //ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID - //convert in to EscherClientDataRecord on the fly - if(r != null && !(r instanceof EscherClientDataRecord)){ - byte[] data = r.serialize(); - r = new EscherClientDataRecord(); - r.fillFields(data, 0, new DefaultEscherRecordFactory()); - } - _clientData = (EscherClientDataRecord)r; - } - if(_clientData != null && _clientRecords == null){ - byte[] data = _clientData.getRemainingData(); - _clientRecords = Record.findChildRecords(data, 0, data.length); - } - return _clientRecords; - } - - protected void updateClientData() { - if(_clientData != null && _clientRecords != null){ - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - for (int i = 0; i < _clientRecords.length; i++) { - _clientRecords[i].writeOut(out); - } - } catch(Exception e){ - throw new HSLFException(e); - } - _clientData.setRemainingData(out.toByteArray()); - } - } - - public void setHyperlink(Hyperlink link){ - if(link.getId() == -1){ - throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first"); - } - - EscherClientDataRecord cldata = new EscherClientDataRecord(); - cldata.setOptions((short)0xF); - getSpContainer().addChildRecord(cldata); // TODO - junit to prove getChildRecords().add is wrong - - InteractiveInfo info = new InteractiveInfo(); - InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); - - switch(link.getType()){ - case Hyperlink.LINK_FIRSTSLIDE: - infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); - infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide); - break; - case Hyperlink.LINK_LASTSLIDE: - infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); - infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide); - break; - case Hyperlink.LINK_NEXTSLIDE: - infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); - infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide); - break; - case Hyperlink.LINK_PREVIOUSSLIDE: - infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); - infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide); - break; - case Hyperlink.LINK_URL: - infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK); - infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url); - break; - case Hyperlink.LINK_SLIDENUMBER: - infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK); - infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber); - break; - } - - infoAtom.setHyperlinkID(link.getId()); - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - try { - info.writeOut(out); - } catch(Exception e){ - throw new HSLFException(e); - } - cldata.setRemainingData(out.toByteArray()); - - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlide.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlide.java deleted file mode 100644 index 7030ce73e1..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlide.java +++ /dev/null @@ -1,515 +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 java.awt.Graphics2D; -import java.util.LinkedList; -import java.util.List; - -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherDgRecord; -import org.apache.poi.ddf.EscherDggRecord; -import org.apache.poi.ddf.EscherSpRecord; -import org.apache.poi.hslf.record.ColorSchemeAtom; -import org.apache.poi.hslf.record.Comment2000; -import org.apache.poi.hslf.record.EscherTextboxWrapper; -import org.apache.poi.hslf.record.HeadersFootersContainer; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordContainer; -import org.apache.poi.hslf.record.RecordTypes; -import org.apache.poi.hslf.record.SSSlideInfoAtom; -import org.apache.poi.hslf.record.SlideAtom; -import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; -import org.apache.poi.hslf.record.StyleTextProp9Atom; -import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.ShapeType; -import org.apache.poi.sl.usermodel.Slide; - -/** - * This class represents a slide in a PowerPoint Document. It allows - * access to the text within, and the layout. For now, it only does - * the text side of things though - * - * @author Nick Burch - * @author Yegor Kozlov - */ - -public final class HSLFSlide extends HSLFSheet implements Slide { - private int _slideNo; - private SlideAtomsSet _atomSet; - private HSLFTextParagraph[] _runs; - private HSLFNotes _notes; // usermodel needs to set this - - /** - * Constructs a Slide from the Slide record, and the SlideAtomsSet - * containing the text. - * Initializes TextRuns, to provide easier access to the text - * - * @param slide the Slide record we're based on - * @param notes the Notes sheet attached to us - * @param atomSet the SlideAtomsSet to get the text from - */ - public HSLFSlide(org.apache.poi.hslf.record.Slide slide, HSLFNotes notes, SlideAtomsSet atomSet, int slideIdentifier, int slideNumber) { - super(slide, slideIdentifier); - - _notes = notes; - _atomSet = atomSet; - _slideNo = slideNumber; - - // Grab the TextRuns from the PPDrawing - HSLFTextParagraph[] _otherRuns = findTextRuns(getPPDrawing()); - - // For the text coming in from the SlideAtomsSet: - // Build up TextRuns from pairs of TextHeaderAtom and - // one of TextBytesAtom or TextCharsAtom - final List textParagraphs = new LinkedList(); - if(_atomSet != null) { - findTextParagraphs(_atomSet.getSlideRecords(),textParagraphs); - } else { - // No text on the slide, must just be pictures - } - - // Build an array, more useful than a vector - _runs = new HSLFTextParagraph[textParagraphs.size()+_otherRuns.length]; - // Grab text from SlideListWithTexts entries - int i=0; - for(HSLFTextParagraph tp : textParagraphs) { - _runs[i++] = tp; - tp.supplySheet(this); - } - // Grab text from slide's PPDrawing - for(HSLFTextParagraph tp : _otherRuns) { - _runs[i++] = tp; - tp.supplySheet(this); - tp.setIndex(-1); // runs found in PPDrawing are not linked with SlideListWithTexts - } - } - - /** - * Create a new Slide instance - * @param sheetNumber The internal number of the sheet, as used by PersistPtrHolder - * @param slideNumber The user facing number of the sheet - */ - public HSLFSlide(int sheetNumber, int sheetRefId, int slideNumber){ - super(new org.apache.poi.hslf.record.Slide(), sheetNumber); - _slideNo = slideNumber; - getSheetContainer().setSheetId(sheetRefId); - } - - /** - * Sets the Notes that are associated with this. Updates the - * references in the records to point to the new ID - */ - public void setNotes(HSLFNotes notes) { - _notes = notes; - - // Update the Slide Atom's ID of where to point to - SlideAtom sa = getSlideRecord().getSlideAtom(); - - if(notes == null) { - // Set to 0 - sa.setNotesID(0); - } else { - // Set to the value from the notes' sheet id - sa.setNotesID(notes._getSheetNumber()); - } - } - - /** - * Changes the Slide's (external facing) page number. - * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#reorderSlide(int, int) - */ - public void setSlideNumber(int newSlideNumber) { - _slideNo = newSlideNumber; - } - - /** - * Called by SlideShow ater a new slide is created. - *

- * For Slide we need to do the following: - *

  • set id of the drawing group. - *
  • set shapeId for the container descriptor and background - *

    - */ - public void onCreate(){ - //initialize drawing group id - EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); - EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0]; - EscherDgRecord dg = (EscherDgRecord) HSLFShape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID); - int dgId = dgg.getMaxDrawingGroupId() + 1; - dg.setOptions((short)(dgId << 4)); - dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); - dgg.setMaxDrawingGroupId(dgId); - - for (EscherContainerRecord c : dgContainer.getChildContainers()) { - EscherSpRecord spr = null; - switch(c.getRecordId()){ - case EscherContainerRecord.SPGR_CONTAINER: - EscherContainerRecord dc = (EscherContainerRecord)c.getChild(0); - spr = dc.getChildById(EscherSpRecord.RECORD_ID); - break; - case EscherContainerRecord.SP_CONTAINER: - spr = c.getChildById(EscherSpRecord.RECORD_ID); - break; - } - if(spr != null) spr.setShapeId(allocateShapeId()); - } - - //PPT doen't increment the number of saved shapes for group descriptor and background - dg.setNumShapes(1); - } - - /** - * Create a TextBox object that represents the slide's title. - * - * @return TextBox object that represents the slide's title. - */ - public HSLFTextBox addTitle() { - Placeholder pl = new Placeholder(); - pl.setShapeType(ShapeType.RECT); - pl.getTextParagraph().setRunType(TextHeaderAtom.TITLE_TYPE); - pl.setText("Click to edit title"); - pl.setAnchor(new java.awt.Rectangle(54, 48, 612, 90)); - addShape(pl); - return pl; - } - - - // Complex Accesser methods follow - - /** - * Return title of this slide or null if the slide does not have title. - *

    - * The title is a run of text of type TextHeaderAtom.CENTER_TITLE_TYPE or - * TextHeaderAtom.TITLE_TYPE - *

    - * - * @see TextHeaderAtom - * - * @return title of this slide - */ - public String getTitle(){ - HSLFTextParagraph[] txt = getTextRuns(); - for (int i = 0; i < txt.length; i++) { - int type = txt[i].getRunType(); - if (type == TextHeaderAtom.CENTER_TITLE_TYPE || - type == TextHeaderAtom.TITLE_TYPE ){ - String title = txt[i].getText(); - return title; - } - } - return null; - } - - // Simple Accesser methods follow - - /** - * Returns an array of all the TextRuns found - */ - public HSLFTextParagraph[] getTextRuns() { return _runs; } - - /** - * Returns the (public facing) page number of this slide - */ - public int getSlideNumber() { return _slideNo; } - - /** - * Returns the underlying slide record - */ - public org.apache.poi.hslf.record.Slide getSlideRecord() { - return (org.apache.poi.hslf.record.Slide)getSheetContainer(); - } - - /** - * Returns the Notes Sheet for this slide, or null if there isn't one - */ - public HSLFNotes getNotesSheet() { return _notes; } - - /** - * @return set of records inside SlideListWithtext container - * which hold text data for this slide (typically for placeholders). - */ - protected SlideAtomsSet getSlideAtomsSet() { return _atomSet; } - - /** - * Returns master sheet associated with this slide. - * It can be either SlideMaster or TitleMaster objects. - * - * @return the master sheet associated with this slide. - */ - public HSLFMasterSheet getMasterSheet(){ - SlideMaster[] master = getSlideShow().getSlidesMasters(); - SlideAtom sa = getSlideRecord().getSlideAtom(); - int masterId = sa.getMasterID(); - HSLFMasterSheet sheet = null; - for (int i = 0; i < master.length; i++) { - if (masterId == master[i]._getSheetNumber()) { - sheet = master[i]; - break; - } - } - if (sheet == null){ - TitleMaster[] titleMaster = getSlideShow().getTitleMasters(); - if(titleMaster != null) for (int i = 0; i < titleMaster.length; i++) { - if (masterId == titleMaster[i]._getSheetNumber()) { - sheet = titleMaster[i]; - break; - } - } - } - return sheet; - } - - /** - * Change Master of this slide. - */ - public void setMasterSheet(HSLFMasterSheet master){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - int sheetNo = master._getSheetNumber(); - sa.setMasterID(sheetNo); - } - - /** - * Sets whether this slide follows master background - * - * @param flag true if the slide follows master, - * false otherwise - */ - public void setFollowMasterBackground(boolean flag){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - sa.setFollowMasterBackground(flag); - } - - /** - * Whether this slide follows master sheet background - * - * @return true if the slide follows master background, - * false otherwise - */ - public boolean getFollowMasterBackground(){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - return sa.getFollowMasterBackground(); - } - - /** - * Sets whether this slide draws master sheet objects - * - * @param flag true if the slide draws master sheet objects, - * false otherwise - */ - public void setFollowMasterObjects(boolean flag){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - sa.setFollowMasterObjects(flag); - } - - /** - * Whether this slide follows master color scheme - * - * @return true if the slide follows master color scheme, - * false otherwise - */ - public boolean getFollowMasterScheme(){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - return sa.getFollowMasterScheme(); - } - - /** - * Sets whether this slide draws master color scheme - * - * @param flag true if the slide draws master color scheme, - * false otherwise - */ - public void setFollowMasterScheme(boolean flag){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - sa.setFollowMasterScheme(flag); - } - - /** - * Whether this slide draws master sheet objects - * - * @return true if the slide draws master sheet objects, - * false otherwise - */ - public boolean getFollowMasterObjects(){ - SlideAtom sa = getSlideRecord().getSlideAtom(); - return sa.getFollowMasterObjects(); - } - - /** - * Background for this slide. - */ - public HSLFBackground getBackground() { - if(getFollowMasterBackground()) { - return getMasterSheet().getBackground(); - } - return super.getBackground(); - } - - /** - * Color scheme for this slide. - */ - public ColorSchemeAtom getColorScheme() { - if(getFollowMasterScheme()){ - return getMasterSheet().getColorScheme(); - } - return super.getColorScheme(); - } - - /** - * Get the comment(s) for this slide. - * Note - for now, only works on PPT 2000 and - * PPT 2003 files. Doesn't work for PPT 97 - * ones, as they do their comments oddly. - */ - public Comment[] getComments() { - // If there are any, they're in - // ProgTags -> ProgBinaryTag -> BinaryTagData - RecordContainer progTags = (RecordContainer) - getSheetContainer().findFirstOfType( - RecordTypes.ProgTags.typeID - ); - if(progTags != null) { - RecordContainer progBinaryTag = (RecordContainer) - progTags.findFirstOfType( - RecordTypes.ProgBinaryTag.typeID - ); - if(progBinaryTag != null) { - RecordContainer binaryTags = (RecordContainer) - progBinaryTag.findFirstOfType( - RecordTypes.BinaryTagData.typeID - ); - if(binaryTags != null) { - // This is where they'll be - int count = 0; - for(int i=0; i recordMap) { - // check for DocumentEncryptionAtom, which would be at the last offset - // need to ignore already set UserEdit and PersistAtoms - UserEditAtom userEditAtomWithEncryption = null; - for (Map.Entry me : recordMap.descendingMap().entrySet()) { - Record r = me.getValue(); - if (!(r instanceof UserEditAtom)) continue; - UserEditAtom uea = (UserEditAtom)r; - if (uea.getEncryptSessionPersistIdRef() != -1) { - userEditAtomWithEncryption = uea; - break; - } - } - - if (userEditAtomWithEncryption == null) { - dea = null; - return; - } - - Record r = recordMap.get(userEditAtomWithEncryption.getPersistPointersOffset()); - assert(r instanceof PersistPtrHolder); - PersistPtrHolder ptr = (PersistPtrHolder)r; - - Integer encOffset = ptr.getSlideLocationsLookup().get(userEditAtomWithEncryption.getEncryptSessionPersistIdRef()); - assert(encOffset != null); - - r = recordMap.get(encOffset); - if (r == null) { - r = Record.buildRecordAtOffset(docstream, encOffset); - recordMap.put(encOffset, r); - } - assert(r instanceof DocumentEncryptionAtom); - this.dea = (DocumentEncryptionAtom)r; - - CryptoAPIDecryptor dec = (CryptoAPIDecryptor)dea.getEncryptionInfo().getDecryptor(); - String pass = Biff8EncryptionKey.getCurrentUserPassword(); - if(!dec.verifyPassword(pass != null ? pass : Decryptor.DEFAULT_PASSWORD)) { - throw new EncryptedPowerPointFileException("PowerPoint file is encrypted. The correct password needs to be set via Biff8EncryptionKey.setCurrentUserPassword()"); - } - } - - public DocumentEncryptionAtom getDocumentEncryptionAtom() { - return dea; - } - - protected void setPersistId(int persistId) { - if (enc != null && dec != null) { - throw new EncryptedPowerPointFileException("Use instance either for en- or decryption"); - } - - try { - if (enc != null) cipher = enc.initCipherForBlock(cipher, persistId); - if (dec != null) cipher = dec.initCipherForBlock(cipher, persistId); - } catch (GeneralSecurityException e) { - throw new EncryptedPowerPointFileException(e); - } - } - - protected void decryptInit() { - if (dec != null) return; - EncryptionInfo ei = dea.getEncryptionInfo(); - dec = (CryptoAPIDecryptor)ei.getDecryptor(); - } - - protected void encryptInit() { - if (enc != null) return; - EncryptionInfo ei = dea.getEncryptionInfo(); - enc = (CryptoAPIEncryptor)ei.getEncryptor(); - } - - - - protected OutputStream encryptRecord(OutputStream plainStream, int persistId, Record record) { - boolean isPlain = (dea == null - || record instanceof UserEditAtom - || record instanceof PersistPtrHolder - || record instanceof DocumentEncryptionAtom - ); - if (isPlain) return plainStream; - - encryptInit(); - setPersistId(persistId); - - if (cyos == null) { - cyos = new CipherOutputStream(plainStream, cipher); - } - return cyos; - } - - protected void decryptRecord(byte[] docstream, int persistId, int offset) { - if (dea == null) return; - - decryptInit(); - setPersistId(persistId); - - try { - // decrypt header and read length to be decrypted - cipher.update(docstream, offset, 8, docstream, offset); - // decrypt the rest of the record - int rlen = (int)LittleEndian.getUInt(docstream, offset+4); - cipher.update(docstream, offset+8, rlen, docstream, offset+8); - } catch (GeneralSecurityException e) { - throw new CorruptPowerPointFileException(e); - } - } - - protected void decryptPicture(byte[] pictstream, int offset) { - if (dea == null) return; - - decryptInit(); - setPersistId(0); - - try { - // decrypt header and read length to be decrypted - cipher.doFinal(pictstream, offset, 8, pictstream, offset); - int recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); - int recType = LittleEndian.getUShort(pictstream, offset+2); - int rlen = (int)LittleEndian.getUInt(pictstream, offset+4); - offset += 8; - int endOffset = offset + rlen; - - if (recType == 0xF007) { - // TOOD: get a real example file ... to actual test the FBSE entry - // not sure where the foDelay block is - - // File BLIP Store Entry (FBSE) - cipher.doFinal(pictstream, offset, 1, pictstream, offset); // btWin32 - offset++; - cipher.doFinal(pictstream, offset, 1, pictstream, offset); // btMacOS - offset++; - cipher.doFinal(pictstream, offset, 16, pictstream, offset); // rgbUid - offset += 16; - cipher.doFinal(pictstream, offset, 2, pictstream, offset); // tag - offset += 2; - cipher.doFinal(pictstream, offset, 4, pictstream, offset); // size - offset += 4; - cipher.doFinal(pictstream, offset, 4, pictstream, offset); // cRef - offset += 4; - cipher.doFinal(pictstream, offset, 4, pictstream, offset); // foDelay - offset += 4; - cipher.doFinal(pictstream, offset+0, 1, pictstream, offset+0); // unused1 - cipher.doFinal(pictstream, offset+1, 1, pictstream, offset+1); // cbName - cipher.doFinal(pictstream, offset+2, 1, pictstream, offset+2); // unused2 - cipher.doFinal(pictstream, offset+3, 1, pictstream, offset+3); // unused3 - int cbName = LittleEndian.getUShort(pictstream, offset+1); - offset += 4; - if (cbName > 0) { - cipher.doFinal(pictstream, offset, cbName, pictstream, offset); // nameData - offset += cbName; - } - if (offset == endOffset) { - return; // no embedded blip - } - // fall through, read embedded blip now - - // update header data - cipher.doFinal(pictstream, offset, 8, pictstream, offset); - recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); - recType = LittleEndian.getUShort(pictstream, offset+2); - rlen = (int)LittleEndian.getUInt(pictstream, offset+4); - offset += 8; - } - - int rgbUidCnt = (recInst == 0x217 || recInst == 0x3D5 || recInst == 0x46B || recInst == 0x543 || - recInst == 0x6E1 || recInst == 0x6E3 || recInst == 0x6E5 || recInst == 0x7A9) ? 2 : 1; - - for (int i=0; i 0) { - cipher.doFinal(pictstream, offset, cbName, pictstream, offset); // nameData - offset += cbName; - } - if (offset == endOffset) { - return; // no embedded blip - } - // fall through, read embedded blip now - - // update header data - recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); - recType = LittleEndian.getUShort(pictstream, offset+2); - rlen = (int)LittleEndian.getUInt(pictstream, offset+4); - cipher.doFinal(pictstream, offset, 8, pictstream, offset); - offset += 8; - } - - int rgbUidCnt = (recInst == 0x217 || recInst == 0x3D5 || recInst == 0x46B || recInst == 0x543 || - recInst == 0x6E1 || recInst == 0x6E3 || recInst == 0x6E5 || recInst == 0x7A9) ? 2 : 1; - - for (int i=0; i done - return records; - } else { - // need to remove password data - dea = null; - return removeEncryptionRecord(records); - } - } else { - // create password record - if (dea == null) { - dea = new DocumentEncryptionAtom(); - } - EncryptionInfo ei = dea.getEncryptionInfo(); - byte salt[] = ei.getVerifier().getSalt(); - Encryptor enc = ei.getEncryptor(); - if (salt == null) { - enc.confirmPassword(password); - } else { - byte verifier[] = ei.getDecryptor().getVerifier(); - enc.confirmPassword(password, null, null, verifier, salt, null); - } - - // move EncryptionRecord to last slide position - records = normalizeRecords(records); - return addEncryptionRecord(records, dea); - } - } - - /** - * remove duplicated UserEditAtoms and merge PersistPtrHolder. - * Before this method is called, make sure that the offsets are correct, - * i.e. call {@link HSLFSlideShowImpl#updateAndWriteDependantRecords(OutputStream, Map)} - */ - protected static Record[] normalizeRecords(Record records[]) { - // http://msdn.microsoft.com/en-us/library/office/gg615594(v=office.14).aspx - // repeated slideIds can be overwritten, i.e. ignored - - UserEditAtom uea = null; - PersistPtrHolder pph = null; - TreeMap slideLocations = new TreeMap(); - TreeMap recordMap = new TreeMap(); - List obsoleteOffsets = new ArrayList(); - int duplicatedCount = 0; - for (Record r : records) { - assert(r instanceof PositionDependentRecord); - PositionDependentRecord pdr = (PositionDependentRecord)r; - if (pdr instanceof UserEditAtom) { - uea = (UserEditAtom)pdr; - continue; - } - - if (pdr instanceof PersistPtrHolder) { - if (pph != null) { - duplicatedCount++; - } - pph = (PersistPtrHolder)pdr; - for (Map.Entry me : pph.getSlideLocationsLookup().entrySet()) { - Integer oldOffset = slideLocations.put(me.getKey(), me.getValue()); - if (oldOffset != null) obsoleteOffsets.add(oldOffset); - } - continue; - } - - recordMap.put(pdr.getLastOnDiskOffset(), r); - } - recordMap.put(pph.getLastOnDiskOffset(), pph); - recordMap.put(uea.getLastOnDiskOffset(), uea); - - assert(uea != null && pph != null && uea.getPersistPointersOffset() == pph.getLastOnDiskOffset()); - - if (duplicatedCount == 0 && obsoleteOffsets.isEmpty()) { - return records; - } - - uea.setLastUserEditAtomOffset(0); - pph.clear(); - for (Map.Entry me : slideLocations.entrySet()) { - pph.addSlideLookup(me.getKey(), me.getValue()); - } - - for (Integer oldOffset : obsoleteOffsets) { - recordMap.remove(oldOffset); - } - - return recordMap.values().toArray(new Record[recordMap.size()]); - } - - - protected static Record[] removeEncryptionRecord(Record records[]) { - int deaSlideId = -1; - int deaOffset = -1; - PersistPtrHolder ptr = null; - UserEditAtom uea = null; - List recordList = new ArrayList(); - for (Record r : records) { - if (r instanceof DocumentEncryptionAtom) { - deaOffset = ((DocumentEncryptionAtom)r).getLastOnDiskOffset(); - continue; - } else if (r instanceof UserEditAtom) { - uea = (UserEditAtom)r; - deaSlideId = uea.getEncryptSessionPersistIdRef(); - uea.setEncryptSessionPersistIdRef(-1); - } else if (r instanceof PersistPtrHolder) { - ptr = (PersistPtrHolder)r; - } - recordList.add(r); - } - - assert(ptr != null); - if (deaSlideId == -1 && deaOffset == -1) return records; - - TreeMap tm = new TreeMap(ptr.getSlideLocationsLookup()); - ptr.clear(); - int maxSlideId = -1; - for (Map.Entry me : tm.entrySet()) { - if (me.getKey() == deaSlideId || me.getValue() == deaOffset) continue; - ptr.addSlideLookup(me.getKey(), me.getValue()); - maxSlideId = Math.max(me.getKey(), maxSlideId); - } - - uea.setMaxPersistWritten(maxSlideId); - - records = recordList.toArray(new Record[recordList.size()]); - - return records; - } - - - protected static Record[] addEncryptionRecord(Record records[], DocumentEncryptionAtom dea) { - assert(dea != null); - int ueaIdx = -1, ptrIdx = -1, deaIdx = -1, idx = -1; - for (Record r : records) { - idx++; - if (r instanceof UserEditAtom) ueaIdx = idx; - else if (r instanceof PersistPtrHolder) ptrIdx = idx; - else if (r instanceof DocumentEncryptionAtom) deaIdx = idx; - } - assert(ueaIdx != -1 && ptrIdx != -1 && ptrIdx < ueaIdx); - if (deaIdx != -1) { - DocumentEncryptionAtom deaOld = (DocumentEncryptionAtom)records[deaIdx]; - dea.setLastOnDiskOffset(deaOld.getLastOnDiskOffset()); - records[deaIdx] = dea; - return records; - } else { - PersistPtrHolder ptr = (PersistPtrHolder)records[ptrIdx]; - UserEditAtom uea = ((UserEditAtom)records[ueaIdx]); - dea.setLastOnDiskOffset(ptr.getLastOnDiskOffset()-1); - int nextSlideId = uea.getMaxPersistWritten()+1; - ptr.addSlideLookup(nextSlideId, ptr.getLastOnDiskOffset()-1); - uea.setEncryptSessionPersistIdRef(nextSlideId); - uea.setMaxPersistWritten(nextSlideId); - - Record newRecords[] = new Record[records.length+1]; - if (ptrIdx > 0) System.arraycopy(records, 0, newRecords, 0, ptrIdx); - if (ptrIdx < records.length-1) System.arraycopy(records, ptrIdx, newRecords, ptrIdx+1, records.length-ptrIdx); - newRecords[ptrIdx] = dea; - return newRecords; - } - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlideShowImpl.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlideShowImpl.java deleted file mode 100644 index 48e52da65c..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFSlideShowImpl.java +++ /dev/null @@ -1,808 +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 java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.security.GeneralSecurityException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.List; -import java.util.Map; -import java.util.NavigableMap; -import java.util.TreeMap; - -import org.apache.poi.POIDocument; -import org.apache.poi.hpsf.PropertySet; -import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; -import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.hslf.record.CurrentUserAtom; -import org.apache.poi.hslf.record.DocumentEncryptionAtom; -import org.apache.poi.hslf.record.ExOleObjStg; -import org.apache.poi.hslf.record.PersistPtrHolder; -import org.apache.poi.hslf.record.PersistRecord; -import org.apache.poi.hslf.record.PositionDependentRecord; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordTypes; -import org.apache.poi.hslf.record.UserEditAtom; -import org.apache.poi.hslf.usermodel.HSLFObjectData; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptor; -import org.apache.poi.poifs.filesystem.DirectoryNode; -import org.apache.poi.poifs.filesystem.DocumentEntry; -import org.apache.poi.poifs.filesystem.DocumentInputStream; -import org.apache.poi.poifs.filesystem.EntryUtils; -import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.util.LittleEndian; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * This class contains the main functionality for the Powerpoint file - * "reader". It is only a very basic class for now - * - * @author Nick Burch - */ -public final class HSLFSlideShowImpl extends POIDocument { - public static final int UNSET_OFFSET = -1; - - // For logging - private POILogger logger = POILogFactory.getLogger(this.getClass()); - - // Holds metadata on where things are in our document - private CurrentUserAtom currentUser; - - // Low level contents of the file - private byte[] _docstream; - - // Low level contents - private Record[] _records; - - // Raw Pictures contained in the pictures stream - private List _pictures; - - // Embedded objects stored in storage records in the document stream, lazily populated. - private HSLFObjectData[] _objects; - - /** - * Returns the underlying POIFSFileSystem for the document - * that is open. - */ - protected POIFSFileSystem getPOIFSFileSystem() { - return directory.getFileSystem(); - } - - /** - * Returns the directory in the underlying POIFSFileSystem for the - * document that is open. - */ - protected DirectoryNode getPOIFSDirectory() { - return directory; - } - - /** - * Constructs a Powerpoint document from fileName. Parses the document - * and places all the important stuff into data structures. - * - * @param fileName The name of the file to read. - * @throws IOException if there is a problem while parsing the document. - */ - public HSLFSlideShowImpl(String fileName) throws IOException - { - this(new FileInputStream(fileName)); - } - - /** - * Constructs a Powerpoint document from an input stream. Parses the - * document and places all the important stuff into data structures. - * - * @param inputStream the source of the data - * @throws IOException if there is a problem while parsing the document. - */ - public HSLFSlideShowImpl(InputStream inputStream) throws IOException { - //do Ole stuff - this(new POIFSFileSystem(inputStream)); - } - - /** - * Constructs a Powerpoint document from a POIFS Filesystem. Parses the - * document and places all the important stuff into data structures. - * - * @param filesystem the POIFS FileSystem to read from - * @throws IOException if there is a problem while parsing the document. - */ - public HSLFSlideShowImpl(POIFSFileSystem filesystem) throws IOException - { - this(filesystem.getRoot()); - } - - /** - * Constructs a Powerpoint document from a POIFS Filesystem. Parses the - * document and places all the important stuff into data structures. - * - * @param filesystem the POIFS FileSystem to read from - * @throws IOException if there is a problem while parsing the document. - */ - public HSLFSlideShowImpl(NPOIFSFileSystem filesystem) throws IOException - { - this(filesystem.getRoot()); - } - - /** - * Constructs a Powerpoint document from a specific point in a - * POIFS Filesystem. Parses the document and places all the - * important stuff into data structures. - * - * @deprecated Use {@link #HSLFSlideShow(DirectoryNode)} instead - * @param dir the POIFS directory to read from - * @param filesystem the POIFS FileSystem to read from - * @throws IOException if there is a problem while parsing the document. - */ - @Deprecated - public HSLFSlideShowImpl(DirectoryNode dir, POIFSFileSystem filesystem) throws IOException - { - this(dir); - } - - /** - * Constructs a Powerpoint document from a specific point in a - * POIFS Filesystem. Parses the document and places all the - * important stuff into data structures. - * - * @param dir the POIFS directory to read from - * @throws IOException if there is a problem while parsing the document. - */ - public HSLFSlideShowImpl(DirectoryNode dir) throws IOException { - super(handleDualStorage(dir)); - - // First up, grab the "Current User" stream - // We need this before we can detect Encrypted Documents - readCurrentUserStream(); - - // Next up, grab the data that makes up the - // PowerPoint stream - readPowerPointStream(); - - // Now, build records based on the PowerPoint stream - buildRecords(); - - // Look for any other streams - readOtherStreams(); - } - - private static DirectoryNode handleDualStorage(DirectoryNode dir) throws IOException { - // when there's a dual storage entry, use it, as the outer document can't be read quite probably ... - String dualName = "PP97_DUALSTORAGE"; - if (!dir.hasEntry(dualName)) return dir; - dir = (DirectoryNode)dir.getEntry(dualName); - return dir; - } - - /** - * Constructs a new, empty, Powerpoint document. - */ - public static final HSLFSlideShowImpl create() { - InputStream is = HSLFSlideShowImpl.class.getResourceAsStream("data/empty.ppt"); - if (is == null) { - throw new RuntimeException("Missing resource 'empty.ppt'"); - } - try { - return new HSLFSlideShowImpl(is); - } catch (IOException e) { - throw new RuntimeException(e); - } - } - - /** - * Extracts the main PowerPoint document stream from the - * POI file, ready to be passed - * - * @throws IOException - */ - private void readPowerPointStream() throws IOException - { - // Get the main document stream - DocumentEntry docProps = - (DocumentEntry)directory.getEntry("PowerPoint Document"); - - // Grab the document stream - _docstream = new byte[docProps.getSize()]; - directory.createDocumentInputStream("PowerPoint Document").read(_docstream); - } - - /** - * Builds the list of records, based on the contents - * of the PowerPoint stream - */ - private void buildRecords() - { - // The format of records in a powerpoint file are: - // - // - // - // If it has a zero length, following it will be another record - // - // If it has a length, depending on its type it may have children or data - // If it has children, these will follow straight away - // > - // If it has data, this will come straigh after, and run for the length - // - // All lengths given exclude the 8 byte record header - // (Data records are known as Atoms) - - // Document should start with: - // 0F 00 E8 03 ## ## ## ## - // (type 1000 = document, info 00 0f is normal, rest is document length) - // 01 00 E9 03 28 00 00 00 - // (type 1001 = document atom, info 00 01 normal, 28 bytes long) - // 80 16 00 00 E0 10 00 00 xx xx xx xx xx xx xx xx - // 05 00 00 00 0A 00 00 00 xx xx xx - // (the contents of the document atom, not sure what it means yet) - // (records then follow) - - // When parsing a document, look to see if you know about that type - // of the current record. If you know it's a type that has children, - // process the record's data area looking for more records - // If you know about the type and it doesn't have children, either do - // something with the data (eg TextRun) or skip over it - // If you don't know about the type, play safe and skip over it (using - // its length to know where the next record will start) - // - - _records = read(_docstream, (int)currentUser.getCurrentEditOffset()); - } - - private Record[] read(byte[] docstream, int usrOffset){ - //sort found records by offset. - //(it is not necessary but SlideShow.findMostRecentCoreRecords() expects them sorted) - NavigableMap records = new TreeMap(); // offset -> record - Map persistIds = new HashMap(); // offset -> persistId - initRecordOffsets(docstream, usrOffset, records, persistIds); - HSLFSlideShowEncrypted decryptData = new HSLFSlideShowEncrypted(docstream, records); - - for (Map.Entry entry : records.entrySet()) { - Integer offset = entry.getKey(); - Record record = entry.getValue(); - Integer persistId = persistIds.get(offset); - if (record == null) { - // all plain records have been already added, - // only new records need to be decrypted (tbd #35897) - decryptData.decryptRecord(docstream, persistId, offset); - record = Record.buildRecordAtOffset(docstream, offset); - entry.setValue(record); - } - - if (record instanceof PersistRecord) { - ((PersistRecord)record).setPersistId(persistId); - } - } - - return records.values().toArray(new Record[records.size()]); - } - - private void initRecordOffsets(byte[] docstream, int usrOffset, NavigableMap recordMap, Map offset2id) { - while (usrOffset != 0){ - UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset); - recordMap.put(usrOffset, usr); - - int psrOffset = usr.getPersistPointersOffset(); - PersistPtrHolder ptr = (PersistPtrHolder)Record.buildRecordAtOffset(docstream, psrOffset); - recordMap.put(psrOffset, ptr); - - for(Map.Entry entry : ptr.getSlideLocationsLookup().entrySet()) { - Integer offset = entry.getValue(); - Integer id = entry.getKey(); - recordMap.put(offset, null); // reserve a slot for the record - offset2id.put(offset, id); - } - - usrOffset = usr.getLastUserEditAtomOffset(); - - // check for corrupted user edit atom and try to repair it - // if the next user edit atom offset is already known, we would go into an endless loop - if (usrOffset > 0 && recordMap.containsKey(usrOffset)) { - // a user edit atom is usually located 36 byte before the smallest known record offset - usrOffset = recordMap.firstKey()-36; - // check that we really are located on a user edit atom - int ver_inst = LittleEndian.getUShort(docstream, usrOffset); - int type = LittleEndian.getUShort(docstream, usrOffset+2); - int len = LittleEndian.getInt(docstream, usrOffset+4); - if (ver_inst == 0 && type == 4085 && (len == 0x1C || len == 0x20)) { - logger.log(POILogger.WARN, "Repairing invalid user edit atom"); - usr.setLastUserEditAtomOffset(usrOffset); - } else { - throw new CorruptPowerPointFileException("Powerpoint document contains invalid user edit atom"); - } - } - } - } - - public DocumentEncryptionAtom getDocumentEncryptionAtom() { - for (Record r : _records) { - if (r instanceof DocumentEncryptionAtom) { - return (DocumentEncryptionAtom)r; - } - } - return null; - } - - - /** - * Find the "Current User" stream, and load it - */ - private void readCurrentUserStream() { - try { - currentUser = new CurrentUserAtom(directory); - } catch(IOException ie) { - logger.log(POILogger.ERROR, "Error finding Current User Atom:\n" + ie); - currentUser = new CurrentUserAtom(); - } - } - - /** - * Find any other streams from the filesystem, and load them - */ - private void readOtherStreams() { - // Currently, there aren't any - } - - /** - * Find and read in pictures contained in this presentation. - * This is lazily called as and when we want to touch pictures. - */ - @SuppressWarnings("unused") - private void readPictures() throws IOException { - _pictures = new ArrayList(); - - // if the presentation doesn't contain pictures - will use a null set instead - if (!directory.hasEntry("Pictures")) return; - - HSLFSlideShowEncrypted decryptData = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); - - DocumentEntry entry = (DocumentEntry)directory.getEntry("Pictures"); - byte[] pictstream = new byte[entry.getSize()]; - DocumentInputStream is = directory.createDocumentInputStream(entry); - is.read(pictstream); - is.close(); - - - int pos = 0; - // An empty picture record (length 0) will take up 8 bytes - while (pos <= (pictstream.length-8)) { - int offset = pos; - - decryptData.decryptPicture(pictstream, offset); - - // Image signature - int signature = LittleEndian.getUShort(pictstream, pos); - pos += LittleEndian.SHORT_SIZE; - // Image type + 0xF018 - int type = LittleEndian.getUShort(pictstream, pos); - pos += LittleEndian.SHORT_SIZE; - // Image size (excluding the 8 byte header) - int imgsize = LittleEndian.getInt(pictstream, pos); - pos += LittleEndian.INT_SIZE; - - // When parsing the BStoreDelay stream, [MS-ODRAW] says that we - // should terminate if the type isn't 0xf007 or 0xf018->0xf117 - if (!((type == 0xf007) || (type >= 0xf018 && type <= 0xf117))) - break; - - // The image size must be 0 or greater - // (0 is allowed, but odd, since we do wind on by the header each - // time, so we won't get stuck) - if(imgsize < 0) { - throw new CorruptPowerPointFileException("The file contains a picture, at position " + _pictures.size() + ", which has a negatively sized data length, so we can't trust any of the picture data"); - } - - // If they type (including the bonus 0xF018) is 0, skip it - if(type == 0) { - logger.log(POILogger.ERROR, "Problem reading picture: Invalid image type 0, on picture with length " + imgsize + ".\nYou document will probably become corrupted if you save it!"); - logger.log(POILogger.ERROR, "" + pos); - } else { - // Build the PictureData object from the data - try { - HSLFPictureData pict = HSLFPictureData.create(type - 0xF018); - - // Copy the data, ready to pass to PictureData - byte[] imgdata = new byte[imgsize]; - System.arraycopy(pictstream, pos, imgdata, 0, imgdata.length); - pict.setRawData(imgdata); - - pict.setOffset(offset); - _pictures.add(pict); - } catch(IllegalArgumentException e) { - logger.log(POILogger.ERROR, "Problem reading picture: " + e + "\nYou document will probably become corrupted if you save it!"); - } - } - - pos += imgsize; - } - } - - /** - * remove duplicated UserEditAtoms and merge PersistPtrHolder, i.e. - * remove document edit history - */ - public void normalizeRecords() { - try { - updateAndWriteDependantRecords(null, null); - } catch (IOException e) { - throw new CorruptPowerPointFileException(e); - } - _records = HSLFSlideShowEncrypted.normalizeRecords(_records); - } - - - /** - * This is a helper functions, which is needed for adding new position dependent records - * or finally write the slideshow to a file. - * - * @param os the stream to write to, if null only the references are updated - * @param interestingRecords a map of interesting records (PersistPtrHolder and UserEditAtom) - * referenced by their RecordType. Only the very last of each type will be saved to the map. - * May be null, if not needed. - * @throws IOException - */ - public void updateAndWriteDependantRecords(OutputStream os, Map interestingRecords) - throws IOException { - // For position dependent records, hold where they were and now are - // As we go along, update, and hand over, to any Position Dependent - // records we happen across - Hashtable oldToNewPositions = new Hashtable(); - - // First pass - figure out where all the position dependent - // records are going to end up, in the new scheme - // (Annoyingly, some powerpoint files have PersistPtrHolders - // that reference slides after the PersistPtrHolder) - UserEditAtom usr = null; - PersistPtrHolder ptr = null; - CountingOS cos = new CountingOS(); - for (Record record : _records) { - // all top level records are position dependent - assert(record instanceof PositionDependentRecord); - PositionDependentRecord pdr = (PositionDependentRecord)record; - int oldPos = pdr.getLastOnDiskOffset(); - int newPos = cos.size(); - pdr.setLastOnDiskOffset(newPos); - if (oldPos != UNSET_OFFSET) { - // new records don't need a mapping, as they aren't in a relation yet - oldToNewPositions.put(oldPos,newPos); - } - - // Grab interesting records as they come past - // this will only save the very last record of each type - RecordTypes.Type saveme = null; - int recordType = (int)record.getRecordType(); - if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) { - saveme = RecordTypes.PersistPtrIncrementalBlock; - ptr = (PersistPtrHolder)pdr; - } else if (recordType == RecordTypes.UserEditAtom.typeID) { - saveme = RecordTypes.UserEditAtom; - usr = (UserEditAtom)pdr; - } - if (interestingRecords != null && saveme != null) { - interestingRecords.put(saveme,pdr); - } - - // Dummy write out, so the position winds on properly - record.writeOut(cos); - } - - assert(usr != null && ptr != null); - - Map persistIds = new HashMap(); - for (Map.Entry entry : ptr.getSlideLocationsLookup().entrySet()) { - persistIds.put(oldToNewPositions.get(entry.getValue()), entry.getKey()); - } - - HSLFSlideShowEncrypted encData = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); - - for (Record record : _records) { - assert(record instanceof PositionDependentRecord); - // We've already figured out their new location, and - // told them that - // Tell them of the positions of the other records though - PositionDependentRecord pdr = (PositionDependentRecord)record; - Integer persistId = persistIds.get(pdr.getLastOnDiskOffset()); - if (persistId == null) persistId = 0; - - // For now, we're only handling PositionDependentRecord's that - // happen at the top level. - // In future, we'll need the handle them everywhere, but that's - // a bit trickier - pdr.updateOtherRecordReferences(oldToNewPositions); - - // Whatever happens, write out that record tree - if (os != null) { - record.writeOut(encData.encryptRecord(os, persistId, record)); - } - } - - // Update and write out the Current User atom - int oldLastUserEditAtomPos = (int)currentUser.getCurrentEditOffset(); - Integer newLastUserEditAtomPos = oldToNewPositions.get(oldLastUserEditAtomPos); - if(usr == null || newLastUserEditAtomPos == null || usr.getLastOnDiskOffset() != newLastUserEditAtomPos) { - throw new HSLFException("Couldn't find the new location of the last UserEditAtom that used to be at " + oldLastUserEditAtomPos); - } - currentUser.setCurrentEditOffset(usr.getLastOnDiskOffset()); - } - - /** - * Writes out the slideshow file the is represented by an instance - * of this class. - * It will write out the common OLE2 streams. If you require all - * streams to be written out, pass in preserveNodes - * @param out The OutputStream to write to. - * @throws IOException If there is an unexpected IOException from - * the passed in OutputStream - */ - public void write(OutputStream out) throws IOException { - // Write out, but only the common streams - write(out,false); - } - /** - * Writes out the slideshow file the is represented by an instance - * of this class. - * If you require all streams to be written out (eg Marcos, embeded - * documents), then set preserveNodes to true - * @param out The OutputStream to write to. - * @param preserveNodes Should all OLE2 streams be written back out, or only the common ones? - * @throws IOException If there is an unexpected IOException from - * the passed in OutputStream - */ - public void write(OutputStream out, boolean preserveNodes) throws IOException { - // read properties and pictures, with old encryption settings where appropriate - if(_pictures == null) { - readPictures(); - } - getDocumentSummaryInformation(); - - // set new encryption settings - HSLFSlideShowEncrypted encryptedSS = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); - _records = encryptedSS.updateEncryptionRecord(_records); - - // Get a new Filesystem to write into - POIFSFileSystem outFS = new POIFSFileSystem(); - - // The list of entries we've written out - List writtenEntries = new ArrayList(1); - - // Write out the Property Streams - writeProperties(outFS, writtenEntries); - - BufAccessBAOS baos = new BufAccessBAOS(); - - // For position dependent records, hold where they were and now are - // As we go along, update, and hand over, to any Position Dependent - // records we happen across - updateAndWriteDependantRecords(baos, null); - - // Update our cached copy of the bytes that make up the PPT stream - _docstream = new byte[baos.size()]; - System.arraycopy(baos.getBuf(), 0, _docstream, 0, baos.size()); - - // Write the PPT stream into the POIFS layer - ByteArrayInputStream bais = new ByteArrayInputStream(_docstream); - outFS.createDocument(bais,"PowerPoint Document"); - writtenEntries.add("PowerPoint Document"); - - currentUser.setEncrypted(encryptedSS.getDocumentEncryptionAtom() != null); - currentUser.writeToFS(outFS); - writtenEntries.add("Current User"); - - - if (_pictures.size() > 0) { - BufAccessBAOS pict = new BufAccessBAOS(); - for (HSLFPictureData p : _pictures) { - int offset = pict.size(); - p.write(pict); - encryptedSS.encryptPicture(pict.getBuf(), offset); - } - outFS.createDocument( - new ByteArrayInputStream(pict.getBuf(), 0, pict.size()), "Pictures" - ); - writtenEntries.add("Pictures"); - } - - // If requested, write out any other streams we spot - if(preserveNodes) { - EntryUtils.copyNodes(directory.getFileSystem(), outFS, writtenEntries); - } - - // Send the POIFSFileSystem object out to the underlying stream - outFS.writeFilesystem(out); - } - - /** - * For a given named property entry, either return it or null if - * if it wasn't found - * - * @param setName The property to read - * @return The value of the given property or null if it wasn't found. - */ - protected PropertySet getPropertySet(String setName) { - DocumentEncryptionAtom dea = getDocumentEncryptionAtom(); - return (dea == null) - ? super.getPropertySet(setName) - : super.getPropertySet(setName, dea.getEncryptionInfo()); - } - - /** - * Writes out the standard Documment Information Properties (HPSF) - * @param outFS the POIFSFileSystem to write the properties into - * @param writtenEntries a list of POIFS entries to add the property names too - * - * @throws IOException if an error when writing to the - * {@link POIFSFileSystem} occurs - */ - protected void writeProperties(POIFSFileSystem outFS, List writtenEntries) throws IOException { - super.writeProperties(outFS, writtenEntries); - DocumentEncryptionAtom dea = getDocumentEncryptionAtom(); - if (dea != null) { - CryptoAPIEncryptor enc = (CryptoAPIEncryptor)dea.getEncryptionInfo().getEncryptor(); - try { - enc.getDataStream(outFS.getRoot()); // ignore OutputStream - } catch (IOException e) { - throw e; - } catch (GeneralSecurityException e) { - throw new IOException(e); - } - } - } - - /* ******************* adding methods follow ********************* */ - - /** - * Adds a new root level record, at the end, but before the last - * PersistPtrIncrementalBlock. - */ - public synchronized int appendRootLevelRecord(Record newRecord) { - int addedAt = -1; - Record[] r = new Record[_records.length+1]; - boolean added = false; - for(int i=(_records.length-1); i>=0; i--) { - if(added) { - // Just copy over - r[i] = _records[i]; - } else { - r[(i+1)] = _records[i]; - if(_records[i] instanceof PersistPtrHolder) { - r[i] = newRecord; - added = true; - addedAt = i; - } - } - } - _records = r; - return addedAt; - } - - /** - * Add a new picture to this presentation. - * - * @return offset of this picture in the Pictures stream - */ - public int addPicture(HSLFPictureData img) { - // Process any existing pictures if we haven't yet - if(_pictures == null) { - try { - readPictures(); - } catch(IOException e) { - throw new CorruptPowerPointFileException(e.getMessage()); - } - } - - // Add the new picture in - int offset = 0; - if(_pictures.size() > 0) { - HSLFPictureData prev = _pictures.get(_pictures.size() - 1); - offset = prev.getOffset() + prev.getRawData().length + 8; - } - img.setOffset(offset); - _pictures.add(img); - return offset; - } - - /* ******************* fetching methods follow ********************* */ - - - /** - * Returns an array of all the records found in the slideshow - */ - public Record[] getRecords() { return _records; } - - /** - * Returns an array of the bytes of the file. Only correct after a - * call to open or write - at all other times might be wrong! - */ - public byte[] getUnderlyingBytes() { return _docstream; } - - /** - * Fetch the Current User Atom of the document - */ - public CurrentUserAtom getCurrentUserAtom() { return currentUser; } - - /** - * Return array of pictures contained in this presentation - * - * @return array with the read pictures or null if the - * presentation doesn't contain pictures. - */ - public HSLFPictureData[] getPictures() { - if(_pictures == null) { - try { - readPictures(); - } catch(IOException e) { - throw new CorruptPowerPointFileException(e.getMessage()); - } - } - - return _pictures.toArray(new HSLFPictureData[_pictures.size()]); - } - - /** - * Gets embedded object data from the slide show. - * - * @return the embedded objects. - */ - public HSLFObjectData[] getEmbeddedObjects() { - if (_objects == null) { - List objects = new ArrayList(); - for (Record r : _records) { - if (r instanceof ExOleObjStg) { - objects.add(new HSLFObjectData((ExOleObjStg)r)); - } - } - _objects = objects.toArray(new HSLFObjectData[objects.size()]); - } - return _objects; - } - - - private static class BufAccessBAOS extends ByteArrayOutputStream { - public byte[] getBuf() { - return buf; - } - } - - private static class CountingOS extends OutputStream { - int count = 0; - public void write(int b) throws IOException { - count++; - } - - public void write(byte[] b) throws IOException { - count += b.length; - } - - public void write(byte[] b, int off, int len) throws IOException { - count += len; - } - - public int size() { - return count; - } - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextBox.java deleted file mode 100644 index 25ea585c95..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextBox.java +++ /dev/null @@ -1,92 +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.sl.usermodel.ShapeContainer; -import org.apache.poi.sl.usermodel.ShapeType; - -/** - * Represents a TextFrame shape in PowerPoint. - *

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

    - * - * @author Yegor Kozlov - */ -public class HSLFTextBox extends HSLFTextShape { - - /** - * Create a TextBox object and initialize it from the supplied Record container. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of the shape - */ - protected HSLFTextBox(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - - } - - /** - * Create a new TextBox. This constructor is used when a new shape is created. - * - * @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 HSLFTextBox(ShapeContainer parent){ - super(parent); - } - - /** - * Create a new TextBox. This constructor is used when a new shape is created. - * - */ - public HSLFTextBox(){ - this(null); - } - - /** - * Create a new TextBox and initialize its internal structures - * - * @return the created EscherContainerRecord which holds shape data - */ - protected EscherContainerRecord createSpContainer(boolean isChild){ - _escherContainer = super.createSpContainer(isChild); - - setShapeType(ShapeType.TEXT_BOX); - - //set default properties for a TextBox - setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); - setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000); - setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100000); - setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001); - setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000); - setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); - - _txtrun = createTextRun(); - - return _escherContainer; - } - - protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ - setVerticalAlignment(HSLFTextBox.AnchorTop); - setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002); - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextParagraph.java deleted file mode 100644 index b23c997dbe..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextParagraph.java +++ /dev/null @@ -1,744 +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 java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; - -import org.apache.poi.hslf.model.textproperties.TextPropCollection; -import org.apache.poi.hslf.record.PPDrawing; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordContainer; -import org.apache.poi.hslf.record.SlideListWithText; -import org.apache.poi.hslf.record.StyleTextProp9Atom; -import org.apache.poi.hslf.record.StyleTextPropAtom; -import org.apache.poi.hslf.record.TextBytesAtom; -import org.apache.poi.hslf.record.TextCharsAtom; -import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.record.TextRulerAtom; -import org.apache.poi.hslf.record.TextSpecInfoAtom; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.sl.usermodel.TextParagraph; -import org.apache.poi.util.StringUtil; - -/** - * This class represents a run of text in a powerpoint document. That - * run could be text on a sheet, or text in a note. - * It is only a very basic class for now - * - * @author Nick Burch - */ - -public final class HSLFTextParagraph implements TextParagraph -{ - // Note: These fields are protected to help with unit testing - // Other classes shouldn't really go playing with them! - protected TextHeaderAtom _headerAtom; - protected TextBytesAtom _byteAtom; - protected TextCharsAtom _charAtom; - protected StyleTextPropAtom _styleAtom; - protected TextRulerAtom _ruler; - protected boolean _isUnicode; - protected HSLFTextRun[] _rtRuns; - protected HSLFTextShape _parentShape; - // private SlideShow slideShow; - private HSLFSheet _sheet; - private int shapeId; - private int slwtIndex = -1; //position in the owning SlideListWithText - /** - * all text run records that follow TextHeaderAtom. - * (there can be misc InteractiveInfo, TxInteractiveInfo and other records) - */ - protected Record[] _records; - // private StyleTextPropAtom styleTextPropAtom; - private StyleTextProp9Atom styleTextProp9Atom; - - /** - * Constructs a Text Run from a Unicode text block - * - * @param tha the TextHeaderAtom that defines what's what - * @param tca the TextCharsAtom containing the text - * @param sta the StyleTextPropAtom which defines the character stylings - */ - public HSLFTextParagraph(TextHeaderAtom tha, TextCharsAtom tca, StyleTextPropAtom sta) { - this(tha,null,tca,sta); - } - - /** - * Constructs a Text Run from a Ascii text block - * - * @param tha the TextHeaderAtom that defines what's what - * @param tba the TextBytesAtom containing the text - * @param sta the StyleTextPropAtom which defines the character stylings - */ - public HSLFTextParagraph(TextHeaderAtom tha, TextBytesAtom tba, StyleTextPropAtom sta) { - this(tha,tba,null,sta); - } - - /** - * Internal constructor and initializer - */ - private HSLFTextParagraph(TextHeaderAtom tha, TextBytesAtom tba, TextCharsAtom tca, StyleTextPropAtom sta) { - _headerAtom = tha; - _styleAtom = sta; - if(tba != null) { - _byteAtom = tba; - _isUnicode = false; - } else { - _charAtom = tca; - _isUnicode = true; - } - String runRawText = getText(); - - // Figure out the rich text runs - LinkedList pStyles = new LinkedList(); - LinkedList cStyles = new LinkedList(); - if(_styleAtom != null) { - // Get the style atom to grok itself - _styleAtom.setParentTextSize(runRawText.length()); - pStyles = _styleAtom.getParagraphStyles(); - cStyles = _styleAtom.getCharacterStyles(); - } - buildRichTextRuns(pStyles, cStyles, runRawText); - } - - public void buildRichTextRuns(LinkedList pStyles, LinkedList cStyles, String runRawText){ - - // Handle case of no current style, with a default - if(pStyles.size() == 0 || cStyles.size() == 0) { - _rtRuns = new HSLFTextRun[1]; - _rtRuns[0] = new HSLFTextRun(this, 0, runRawText.length()); - } else { - // Build up Rich Text Runs, one for each - // character/paragraph style pair - List rtrs = new ArrayList(); - - int pos = 0; - - int curP = 0; - int curC = 0; - int pLenRemain = -1; - int cLenRemain = -1; - - // Build one for each run with the same style - while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) { - // Get the Props to use - TextPropCollection pProps = pStyles.get(curP); - TextPropCollection cProps = cStyles.get(curC); - - int pLen = pProps.getCharactersCovered(); - int cLen = cProps.getCharactersCovered(); - - // Handle new pass - boolean freshSet = false; - if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; } - if(pLenRemain == -1) { pLenRemain = pLen; } - if(cLenRemain == -1) { cLenRemain = cLen; } - - // So we know how to build the eventual run - int runLen = -1; - boolean pShared = false; - boolean cShared = false; - - // Same size, new styles - neither shared - if(pLen == cLen && freshSet) { - runLen = cLen; - pShared = false; - cShared = false; - curP++; - curC++; - pLenRemain = -1; - cLenRemain = -1; - } else { - // Some sharing - - // See if we are already in a shared block - if(pLenRemain < pLen) { - // Existing shared p block - pShared = true; - - // Do we end with the c block, or either side of it? - if(pLenRemain == cLenRemain) { - // We end at the same time - cShared = false; - runLen = pLenRemain; - curP++; - curC++; - pLenRemain = -1; - cLenRemain = -1; - } else if(pLenRemain < cLenRemain) { - // We end before the c block - cShared = true; - runLen = pLenRemain; - curP++; - cLenRemain -= pLenRemain; - pLenRemain = -1; - } else { - // We end after the c block - cShared = false; - runLen = cLenRemain; - curC++; - pLenRemain -= cLenRemain; - cLenRemain = -1; - } - } else if(cLenRemain < cLen) { - // Existing shared c block - cShared = true; - - // Do we end with the p block, or either side of it? - if(pLenRemain == cLenRemain) { - // We end at the same time - pShared = false; - runLen = cLenRemain; - curP++; - curC++; - pLenRemain = -1; - cLenRemain = -1; - } else if(cLenRemain < pLenRemain) { - // We end before the p block - pShared = true; - runLen = cLenRemain; - curC++; - pLenRemain -= cLenRemain; - cLenRemain = -1; - } else { - // We end after the p block - pShared = false; - runLen = pLenRemain; - curP++; - cLenRemain -= pLenRemain; - pLenRemain = -1; - } - } else { - // Start of a shared block - if(pLenRemain < cLenRemain) { - // Shared c block - pShared = false; - cShared = true; - runLen = pLenRemain; - curP++; - cLenRemain -= pLenRemain; - pLenRemain = -1; - } else { - // Shared p block - pShared = true; - cShared = false; - runLen = cLenRemain; - curC++; - pLenRemain -= cLenRemain; - cLenRemain = -1; - } - } - } - - // Wind on - int prevPos = pos; - pos += runLen; - // Adjust for end-of-run extra 1 length - if(pos > runRawText.length()) { - runLen--; - } - - // Save - HSLFTextRun rtr = new HSLFTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared); - rtrs.add(rtr); - } - - // Build the array - _rtRuns = rtrs.toArray(new HSLFTextRun[rtrs.size()]); - } - - } - - // Update methods follow - - /** - * Adds the supplied text onto the end of the TextRun, - * creating a new RichTextRun (returned) for it to - * sit in. - * In many cases, before calling this, you'll want to add - * a newline onto the end of your last RichTextRun - */ - public HSLFTextRun appendText(String s) { - // We will need a StyleTextProp atom - ensureStyleAtomPresent(); - - // First up, append the text to the - // underlying text atom - int oldSize = getRawText().length(); - storeText( - getRawText() + s - ); - - // If either of the previous styles overran - // the text by one, we need to shuffle that - // extra character onto the new ones - int pOverRun = _styleAtom.getParagraphTextLengthCovered() - oldSize; - int cOverRun = _styleAtom.getCharacterTextLengthCovered() - oldSize; - if(pOverRun > 0) { - TextPropCollection tpc = _styleAtom.getParagraphStyles().getLast(); - tpc.updateTextSize( - tpc.getCharactersCovered() - pOverRun - ); - } - if(cOverRun > 0) { - TextPropCollection tpc = _styleAtom.getCharacterStyles().getLast(); - tpc.updateTextSize( - tpc.getCharactersCovered() - cOverRun - ); - } - - // Next, add the styles for its paragraph and characters - TextPropCollection newPTP = - _styleAtom.addParagraphTextPropCollection(s.length()+pOverRun); - TextPropCollection newCTP = - _styleAtom.addCharacterTextPropCollection(s.length()+cOverRun); - - // Now, create the new RichTextRun - HSLFTextRun nr = new HSLFTextRun( - this, oldSize, s.length(), - newPTP, newCTP, false, false - ); - - // Add the new RichTextRun onto our list - HSLFTextRun[] newRuns = new HSLFTextRun[_rtRuns.length+1]; - System.arraycopy(_rtRuns, 0, newRuns, 0, _rtRuns.length); - newRuns[newRuns.length-1] = nr; - _rtRuns = newRuns; - - // And return the new run to the caller - return nr; - } - - /** - * Saves the given string to the records. Doesn't - * touch the stylings. - */ - private void storeText(String s) { - // Store in the appropriate record - if(_isUnicode) { - // The atom can safely convert to unicode - _charAtom.setText(s); - } else { - // Will it fit in a 8 bit atom? - boolean hasMultibyte = StringUtil.hasMultibyte(s); - if(! hasMultibyte) { - // Fine to go into 8 bit atom - byte[] text = new byte[s.length()]; - StringUtil.putCompressedUnicode(s,text,0); - _byteAtom.setText(text); - } else { - // Need to swap a TextBytesAtom for a TextCharsAtom - - // Build the new TextCharsAtom - _charAtom = new TextCharsAtom(); - _charAtom.setText(s); - - // Use the TextHeaderAtom to do the swap on the parent - RecordContainer parent = _headerAtom.getParentRecord(); - Record[] cr = parent.getChildRecords(); - for(int i=0; i pStyles = _styleAtom.getParagraphStyles(); - while(pStyles.size() > 1) { pStyles.removeLast(); } - - if (!pStyles.isEmpty()) { - pStyles.getFirst().updateTextSize( s.length()+1 ); - } - - LinkedList cStyles = _styleAtom.getCharacterStyles(); - while(cStyles.size() > 1) { cStyles.removeLast(); } - - if (!cStyles.isEmpty()) { - cStyles.getFirst().updateTextSize( s.length()+1 ); - } - - _rtRuns[0].setText(s); - } else { - // Recreate rich text run with no styling - _rtRuns[0] = new HSLFTextRun(this,0,s.length()); - } - - } - - /** - * Changes the text. - * Converts '\r' into '\n' - */ - public void setText(String s) { - String text = normalize(s); - setRawText(text); - } - - /** - * Ensure a StyleTextPropAtom is present for this run, - * by adding if required. Normally for internal TextRun use. - */ - public void ensureStyleAtomPresent() { - if(_styleAtom != null) { - // All there - return; - } - - // Create a new one at the right size - _styleAtom = new StyleTextPropAtom(getRawText().length() + 1); - - // Use the TextHeader atom to get at the parent - RecordContainer runAtomsParent = _headerAtom.getParentRecord(); - - // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom - Record addAfter = _byteAtom; - if(_byteAtom == null) { addAfter = _charAtom; } - runAtomsParent.addChildAfter(_styleAtom, addAfter); - - // Feed this to our sole rich text run - if(_rtRuns.length != 1) { - throw new IllegalStateException("Needed to add StyleTextPropAtom when had many rich text runs"); - } - // These are the only styles for now - _rtRuns[0].supplyTextProps( - _styleAtom.getParagraphStyles().get(0), - _styleAtom.getCharacterStyles().get(0), - false, - false - ); - } - - // Accesser methods follow - - /** - * Returns the text content of the run, which has been made safe - * for printing and other use. - */ - public String getText() { - String rawText = getRawText(); - - // PowerPoint seems to store files with \r as the line break - // The messes things up on everything but a Mac, so translate - // them to \n - String text = rawText.replace('\r','\n'); - - int type = _headerAtom == null ? 0 : _headerAtom.getTextType(); - if(type == TextHeaderAtom.TITLE_TYPE || type == TextHeaderAtom.CENTER_TITLE_TYPE){ - //0xB acts like cariage return in page titles and like blank in the others - text = text.replace((char) 0x0B, '\n'); - } else { - text = text.replace((char) 0x0B, ' '); - } - return text; - } - - /** - * Returns the raw text content of the run. This hasn't had any - * changes applied to it, and so is probably unlikely to print - * out nicely. - */ - public String getRawText() { - if(_isUnicode) { - return _charAtom.getText(); - } - return _byteAtom.getText(); - } - - /** - * Fetch the rich text runs (runs of text with the same styling) that - * are contained within this block of text - */ - public HSLFTextRun[] getRichTextRuns() { - return _rtRuns; - } - - /** - * Returns the type of the text, from the TextHeaderAtom. - * Possible values can be seen from TextHeaderAtom - * @see org.apache.poi.hslf.record.TextHeaderAtom - */ - public int getRunType() { - return _headerAtom.getTextType(); - } - - /** - * Changes the type of the text. Values should be taken - * from TextHeaderAtom. No checking is done to ensure you - * set this to a valid value! - * @see org.apache.poi.hslf.record.TextHeaderAtom - */ - public void setRunType(int type) { - _headerAtom.setTextType(type); - } - - /** - * Supply the Sheet we belong to, which might have an assigned SlideShow - * Also passes it on to our child RichTextRuns - */ - public void supplySheet(HSLFSheet sheet){ - this._sheet = sheet; - - if (_rtRuns == null) return; - for(HSLFTextRun rt : _rtRuns) { - rt.updateSheet(); - } - } - - public HSLFSheet getSheet(){ - return this._sheet; - } - - /** - * @return Shape ID - */ - protected int getShapeId(){ - return shapeId; - } - - /** - * @param id Shape ID - */ - protected void setShapeId(int id){ - shapeId = id; - } - - /** - * @return 0-based index of the text run in the SLWT container - */ - protected int getIndex(){ - return slwtIndex; - } - - /** - * @param id 0-based index of the text run in the SLWT container - */ - protected void setIndex(int id){ - slwtIndex = id; - } - - /** - * Is this Text Run one from a {@link PPDrawing}, or is it - * one from the {@link SlideListWithText}? - */ - public boolean isDrawingBased() { - return (slwtIndex == -1); - } - - /** - * Returns the array of all hyperlinks in this text run - * - * @return the array of all hyperlinks in this text run - * or null if not found. - */ - public Hyperlink[] getHyperlinks(){ - return Hyperlink.find(this); - } - - /** - * Fetch RichTextRun at a given position - * - * @param pos 0-based index in the text - * @return RichTextRun or null if not found - */ - public HSLFTextRun getRichTextRunAt(int pos){ - for (int i = 0; i < _rtRuns.length; i++) { - int start = _rtRuns[i].getStartIndex(); - int end = _rtRuns[i].getEndIndex(); - if(pos >= start && pos < end) return _rtRuns[i]; - } - return null; - } - - public TextRulerAtom getTextRuler(){ - if(_ruler == null){ - if(_records != null) for (int i = 0; i < _records.length; i++) { - if(_records[i] instanceof TextRulerAtom) { - _ruler = (TextRulerAtom)_records[i]; - break; - } - } - - } - return _ruler; - - } - - public TextRulerAtom createTextRuler(){ - _ruler = getTextRuler(); - if(_ruler == null){ - _ruler = TextRulerAtom.getParagraphInstance(); - _headerAtom.getParentRecord().appendChildRecord(_ruler); - } - return _ruler; - } - - /** - * Returns a new string with line breaks converted into internal ppt representation - */ - public String normalize(String s){ - String ns = s.replaceAll("\\r?\\n", "\r"); - return ns; - } - - /** - * Returns records that make up this text run - * - * @return text run records - */ - public Record[] getRecords(){ - return _records; - } - /** Numbered List info */ - public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) { - this.styleTextProp9Atom = styleTextProp9Atom; - } - /** Numbered List info */ - public StyleTextProp9Atom getStyleTextProp9Atom() { - return this.styleTextProp9Atom; - } - - /** Characters covered */ - public StyleTextPropAtom getStyleTextPropAtom() { - return this._styleAtom; - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextShape.java deleted file mode 100644 index 17e8b81d21..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HSLFTextShape.java +++ /dev/null @@ -1,639 +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 java.awt.Font; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.font.FontRenderContext; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Rectangle2D; -import java.io.IOException; - -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherOptRecord; -import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.ddf.EscherSimpleProperty; -import org.apache.poi.ddf.EscherSpRecord; -import org.apache.poi.ddf.EscherTextboxRecord; -import org.apache.poi.hslf.exceptions.HSLFException; -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.OutlineTextRefAtom; -import org.apache.poi.hslf.record.PPDrawing; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordTypes; -import org.apache.poi.hslf.record.RoundTripHFPlaceholder12; -import org.apache.poi.hslf.record.StyleTextPropAtom; -import org.apache.poi.hslf.record.TextBytesAtom; -import org.apache.poi.hslf.record.TextCharsAtom; -import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.record.TxInteractiveInfoAtom; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.sl.usermodel.ShapeContainer; -import org.apache.poi.util.POILogger; - -/** - * A common superclass of all shapes that can hold text. - * - * @author Yegor Kozlov - */ -public abstract class HSLFTextShape extends HSLFSimpleShape { - - /** - * How to anchor the text - */ - public static final int AnchorTop = 0; - public static final int AnchorMiddle = 1; - public static final int AnchorBottom = 2; - public static final int AnchorTopCentered = 3; - public static final int AnchorMiddleCentered = 4; - public static final int AnchorBottomCentered = 5; - public static final int AnchorTopBaseline = 6; - public static final int AnchorBottomBaseline = 7; - public static final int AnchorTopCenteredBaseline = 8; - public static final int AnchorBottomCenteredBaseline = 9; - - /** - * How to wrap the text - */ - public static final int WrapSquare = 0; - public static final int WrapByPoints = 1; - public static final int WrapNone = 2; - public static final int WrapTopBottom = 3; - public static final int WrapThrough = 4; - - /** - * How to align the text - */ - public static final int AlignLeft = 0; - public static final int AlignCenter = 1; - public static final int AlignRight = 2; - public static final int AlignJustify = 3; - - /** - * TextRun object which holds actual text and format data - */ - protected HSLFTextParagraph _txtrun; - - /** - * Escher container which holds text attributes such as - * TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc. - */ - protected EscherTextboxWrapper _txtbox; - - /** - * Used to calculate text bounds - */ - protected static final FontRenderContext _frc = new FontRenderContext(null, true, true); - - /** - * Create a TextBox object and initialize it from the supplied Record container. - * - * @param escherRecord EscherSpContainer container which holds information about this shape - * @param parent the parent of the shape - */ - protected HSLFTextShape(EscherContainerRecord escherRecord, ShapeContainer parent){ - super(escherRecord, parent); - - } - - /** - * Create a new TextBox. This constructor is used when a new shape is created. - * - * @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 HSLFTextShape(ShapeContainer parent){ - super(null, parent); - _escherContainer = createSpContainer(parent instanceof HSLFGroupShape); - } - - /** - * Create a new TextBox. This constructor is used when a new shape is created. - * - */ - public HSLFTextShape(){ - this(null); - } - - public HSLFTextParagraph createTextRun(){ - _txtbox = getEscherTextboxWrapper(); - if(_txtbox == null) _txtbox = new EscherTextboxWrapper(); - - _txtrun = getTextParagraph(); - if(_txtrun == null){ - TextHeaderAtom tha = new TextHeaderAtom(); - tha.setParentRecord(_txtbox); - _txtbox.appendChildRecord(tha); - - TextCharsAtom tca = new TextCharsAtom(); - _txtbox.appendChildRecord(tca); - - StyleTextPropAtom sta = new StyleTextPropAtom(0); - _txtbox.appendChildRecord(sta); - - _txtrun = new HSLFTextParagraph(tha,tca,sta); - _txtrun._records = new Record[]{tha, tca, sta}; - _txtrun.setText(""); - - _escherContainer.addChildRecord(_txtbox.getEscherRecord()); - - setDefaultTextProperties(_txtrun); - } - - return _txtrun; - } - - /** - * Set default properties for the TextRun. - * Depending on the text and shape type the defaults are different: - * TextBox: align=left, valign=top - * AutoShape: align=center, valign=middle - * - */ - protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ - - } - - /** - * Returns the text contained in this text frame. - * - * @return the text string for this textbox. - */ - public String getText(){ - HSLFTextParagraph tx = getTextParagraph(); - return tx == null ? null : tx.getText(); - } - - /** - * Sets the text contained in this text frame. - * - * @param text the text string used by this object. - */ - public void setText(String text){ - HSLFTextParagraph tx = getTextParagraph(); - if(tx == null){ - tx = createTextRun(); - } - tx.setText(text); - setTextId(text.hashCode()); - } - - /** - * When a textbox is added to a sheet we need to tell upper-level - * PPDrawing about it. - * - * @param sh the sheet we are adding to - */ - protected void afterInsert(HSLFSheet sh){ - super.afterInsert(sh); - - EscherTextboxWrapper _txtbox = getEscherTextboxWrapper(); - if(_txtbox != null){ - PPDrawing ppdrawing = sh.getPPDrawing(); - ppdrawing.addTextboxWrapper(_txtbox); - // Ensure the escher layer knows about the added records - try { - _txtbox.writeOut(null); - } catch (IOException e){ - throw new HSLFException(e); - } - if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText(); - } - if(_txtrun != null) { - _txtrun.setShapeId(getShapeId()); - sh.onAddTextShape(this); - } - } - - protected EscherTextboxWrapper getEscherTextboxWrapper(){ - if(_txtbox == null){ - EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID); - if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord); - } - return _txtbox; - } - /** - * Adjust the size of the TextShape so it encompasses the text inside it. - * - * @return a Rectangle2D that is the bounds of this TextShape. - */ - public Rectangle2D resizeToFitText(){ - String txt = getText(); - if(txt == null || txt.length() == 0) return new Rectangle2D.Float(); - - HSLFTextRun rt = getTextParagraph().getRichTextRuns()[0]; - int size = rt.getFontSize(); - int style = 0; - if (rt.isBold()) style |= Font.BOLD; - if (rt.isItalic()) style |= Font.ITALIC; - String fntname = rt.getFontName(); - Font font = new Font(fntname, style, size); - - float width = 0, height = 0, leading = 0; - String[] lines = txt.split("\n"); - for (int i = 0; i < lines.length; i++) { - if(lines[i].length() == 0) continue; - - TextLayout layout = new TextLayout(lines[i], font, _frc); - - leading = Math.max(leading, layout.getLeading()); - width = Math.max(width, layout.getAdvance()); - height = Math.max(height, (height + (layout.getDescent() + layout.getAscent()))); - } - - // add one character to width - Rectangle2D charBounds = font.getMaxCharBounds(_frc); - width += getMarginLeft() + getMarginRight() + charBounds.getWidth(); - - // add leading to height - height += getMarginTop() + getMarginBottom() + leading; - - Rectangle2D anchor = getAnchor2D(); - anchor.setRect(anchor.getX(), anchor.getY(), width, height); - setAnchor(anchor); - - return anchor; - } - - /** - * Returns the type of vertical alignment for the text. - * One of the Anchor* constants defined in this class. - * - * @return the type of alignment - */ - public int getVerticalAlignment(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT); - int valign = HSLFTextShape.AnchorTop; - if (prop == null){ - /** - * If vertical alignment was not found in the shape properties then try to - * fetch the master shape and search for the align property there. - */ - int type = getTextParagraph().getRunType(); - HSLFMasterSheet master = getSheet().getMasterSheet(); - if(master != null){ - HSLFTextShape masterShape = master.getPlaceholderByTextType(type); - if(masterShape != null) valign = masterShape.getVerticalAlignment(); - } else { - //not found in the master sheet. Use the hardcoded defaults. - switch (type){ - case TextHeaderAtom.TITLE_TYPE: - case TextHeaderAtom.CENTER_TITLE_TYPE: - valign = HSLFTextShape.AnchorMiddle; - break; - default: - valign = HSLFTextShape.AnchorTop; - break; - } - } - } else { - valign = prop.getPropertyValue(); - } - return valign; - } - - /** - * Sets the type of vertical alignment for the text. - * One of the Anchor* constants defined in this class. - * - * @param align - the type of alignment - */ - public void setVerticalAlignment(int align){ - setEscherProperty(EscherProperties.TEXT__ANCHORTEXT, align); - } - - /** - * Sets the type of horizontal alignment for the text. - * One of the Align* constants defined in this class. - * - * @param align - the type of horizontal alignment - */ - public void setHorizontalAlignment(int align){ - HSLFTextParagraph tx = getTextParagraph(); - if(tx != null) tx.getRichTextRuns()[0].setAlignment(align); - } - - /** - * Gets the type of horizontal alignment for the text. - * One of the Align* constants defined in this class. - * - * @return align - the type of horizontal alignment - */ - public int getHorizontalAlignment(){ - HSLFTextParagraph tx = getTextParagraph(); - return tx == null ? -1 : tx.getRichTextRuns()[0].getAlignment(); - } - - /** - * Returns the distance (in points) between the bottom of the text frame - * and the bottom of the inscribed rectangle of the shape that contains the text. - * Default value is 1/20 inch. - * - * @return the botom margin - */ - public float getMarginBottom(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM); - int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue(); - return (float)val/EMU_PER_POINT; - } - - /** - * Sets the botom margin. - * @see #getMarginBottom() - * - * @param margin the bottom margin - */ - public void setMarginBottom(float margin){ - setEscherProperty(EscherProperties.TEXT__TEXTBOTTOM, (int)(margin*EMU_PER_POINT)); - } - - /** - * Returns the distance (in points) between the left edge of the text frame - * and the left edge of the inscribed rectangle of the shape that contains - * the text. - * Default value is 1/10 inch. - * - * @return the left margin - */ - public float getMarginLeft(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT); - int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); - return (float)val/EMU_PER_POINT; - } - - /** - * Sets the left margin. - * @see #getMarginLeft() - * - * @param margin the left margin - */ - public void setMarginLeft(float margin){ - setEscherProperty(EscherProperties.TEXT__TEXTLEFT, (int)(margin*EMU_PER_POINT)); - } - - /** - * Returns the distance (in points) between the right edge of the - * text frame and the right edge of the inscribed rectangle of the shape - * that contains the text. - * Default value is 1/10 inch. - * - * @return the right margin - */ - public float getMarginRight(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT); - int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); - return (float)val/EMU_PER_POINT; - } - - /** - * Sets the right margin. - * @see #getMarginRight() - * - * @param margin the right margin - */ - public void setMarginRight(float margin){ - setEscherProperty(EscherProperties.TEXT__TEXTRIGHT, (int)(margin*EMU_PER_POINT)); - } - - /** - * Returns the distance (in points) between the top of the text frame - * and the top of the inscribed rectangle of the shape that contains the text. - * Default value is 1/20 inch. - * - * @return the top margin - */ - public float getMarginTop(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP); - int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue(); - return (float)val/EMU_PER_POINT; - } - - /** - * Sets the top margin. - * @see #getMarginTop() - * - * @param margin the top margin - */ - public void setMarginTop(float margin){ - setEscherProperty(EscherProperties.TEXT__TEXTTOP, (int)(margin*EMU_PER_POINT)); - } - - - /** - * Returns the value indicating word wrap. - * - * @return the value indicating word wrap. - * Must be one of the Wrap* constants defined in this class. - */ - public int getWordWrap(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT); - return prop == null ? WrapSquare : prop.getPropertyValue(); - } - - /** - * Specifies how the text should be wrapped - * - * @param wrap the value indicating how the text should be wrapped. - * Must be one of the Wrap* constants defined in this class. - */ - public void setWordWrap(int wrap){ - setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap); - } - - /** - * @return id for the text. - */ - public int getTextId(){ - EscherOptRecord opt = getEscherOptRecord(); - EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTID); - return prop == null ? 0 : prop.getPropertyValue(); - } - - /** - * Sets text ID - * - * @param id of the text - */ - public void setTextId(int id){ - setEscherProperty(EscherProperties.TEXT__TEXTID, id); - } - - /** - * @return the TextRun object for this text box - */ - public HSLFTextParagraph getTextParagraph(){ - if (null == this._txtrun) initTextRun(); - if (null == this._txtrun && null != this._txtbox) { - TextHeaderAtom tha = null; - TextBytesAtom tba = null; - TextCharsAtom tca = null; - StyleTextPropAtom sta = null; - Record[] childRecords = this._txtbox.getChildRecords(); - for (Record r : childRecords) { - if (r instanceof TextHeaderAtom) { - tha = (TextHeaderAtom) r; - } else if (r instanceof TextBytesAtom) { - tba = (TextBytesAtom) r; - } else if (r instanceof TextCharsAtom) { - tca = (TextCharsAtom) r; - } else if (r instanceof StyleTextPropAtom) { - sta = (StyleTextPropAtom) r; - } - } - if (tba != null) { - this._txtrun = new HSLFTextParagraph(tha, tba, sta); - } else if (tca != null) { - this._txtrun = new HSLFTextParagraph(tha, tca, sta); - } - } - return _txtrun; - } - - public void setSheet(HSLFSheet sheet) { - _sheet = sheet; - - // Initialize _txtrun object. - // (We can't do it in the constructor because the sheet - // is not assigned then, it's only built once we have - // all the records) - HSLFTextParagraph tx = getTextParagraph(); - if (tx != null) { - // Supply the sheet to our child RichTextRuns - tx.supplySheet(_sheet); - } - } - - protected void initTextRun(){ - EscherTextboxWrapper txtbox = getEscherTextboxWrapper(); - HSLFSheet sheet = getSheet(); - - if(sheet == null || txtbox == null) return; - - OutlineTextRefAtom ota = null; - - Record[] child = txtbox.getChildRecords(); - for (int i = 0; i < child.length; i++) { - if (child[i] instanceof OutlineTextRefAtom) { - ota = (OutlineTextRefAtom)child[i]; - break; - } - } - - HSLFTextParagraph[] runs = _sheet.getTextRuns(); - if (ota != null) { - int idx = ota.getTextIndex(); - for (int i = 0; i < runs.length; i++) { - if(runs[i].getIndex() == idx){ - _txtrun = runs[i]; - break; - } - } - if(_txtrun == null) { - logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx); - } - } else { - EscherSpRecord escherSpRecord = getEscherChild(EscherSpRecord.RECORD_ID); - int shapeId = escherSpRecord.getShapeId(); - if(runs != null) for (int i = 0; i < runs.length; i++) { - if(runs[i].getShapeId() == shapeId){ - _txtrun = runs[i]; - break; - } - } - } - - // ensure the same references child records of TextRun - if(_txtrun != null) { - for (int i = 0; i < child.length; i++) { - for (Record r : _txtrun.getRecords()) { - if (child[i].getRecordType() == r.getRecordType()) { - child[i] = r; - } - } - } - } - } - - public void draw(Graphics2D graphics){ - AffineTransform at = graphics.getTransform(); - ShapePainter.paint(this, graphics); - new TextPainter(this).paint(graphics); - graphics.setTransform(at); - } - - /** - * Return OEPlaceholderAtom, the atom that describes a placeholder. - * - * @return OEPlaceholderAtom or null if not found - */ - public OEPlaceholderAtom getPlaceholderAtom(){ - return getClientDataRecord(RecordTypes.OEPlaceholderAtom.typeID); - } - - /** - * - * Assigns a hyperlink to this text shape - * - * @param linkId id of the hyperlink, @see org.apache.poi.hslf.usermodel.SlideShow#addHyperlink(Hyperlink) - * @param beginIndex the beginning index, inclusive. - * @param endIndex the ending index, exclusive. - * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#addHyperlink(Hyperlink) - */ - public void setHyperlink(int linkId, int beginIndex, int endIndex){ - //TODO validate beginIndex and endIndex and throw IllegalArgumentException - - InteractiveInfo info = new InteractiveInfo(); - InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); - infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK); - infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url); - infoAtom.setHyperlinkID(linkId); - - _txtbox.appendChildRecord(info); - - TxInteractiveInfoAtom txiatom = new TxInteractiveInfoAtom(); - txiatom.setStartIndex(beginIndex); - txiatom.setEndIndex(endIndex); - _txtbox.appendChildRecord(txiatom); - - } - - @Override - public boolean isPlaceholder() { - OEPlaceholderAtom oep = getPlaceholderAtom(); - if (oep != null) return true; - - //special case for files saved in Office 2007 - RoundTripHFPlaceholder12 hldr = getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID); - if (hldr != null) return true; - - return false; - } - - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java b/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java index bd3a6da399..63ec3d7a6f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/HeadersFooters.java @@ -18,7 +18,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.hslf.record.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; /** * Header / Footer settings. @@ -240,7 +240,7 @@ public final class HeadersFooters { private boolean isVisible(int flag, int placeholderId){ boolean visible; if(_ppt2007){ - HSLFSheet master = _sheet != null ? _sheet : _ppt.getSlidesMasters()[0]; + HSLFSheet master = _sheet != null ? _sheet : _ppt.getSlideMasters().get(0); HSLFTextShape placeholder = master.getPlaceholder(placeholderId); visible = placeholder != null && placeholder.getText() != null; } else { @@ -252,7 +252,7 @@ public final class HeadersFooters { private String getPlaceholderText(int placeholderId, CString cs){ String text = null; if(_ppt2007){ - HSLFSheet master = _sheet != null ? _sheet : _ppt.getSlidesMasters()[0]; + HSLFSheet master = _sheet != null ? _sheet : _ppt.getSlideMasters().get(0); HSLFTextShape placeholder = master.getPlaceholder(placeholderId); if(placeholder != null) text = placeholder.getText(); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Hyperlink.java b/src/scratchpad/src/org/apache/poi/hslf/model/Hyperlink.java deleted file mode 100644 index 2e1f1ec586..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Hyperlink.java +++ /dev/null @@ -1,225 +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.hslf.record.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.ddf.EscherClientDataRecord; - -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; - -/** - * Represents a hyperlink in a PowerPoint document - * - * @author Yegor Kozlov - */ -public final class Hyperlink { - public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide; - public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide; - public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide; - public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide; - public static final byte LINK_SLIDENUMBER = InteractiveInfoAtom.LINK_SlideNumber; - public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url; - public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL; - - private int id=-1; - private int type; - private String address; - private String title; - private int startIndex, endIndex; - - /** - * Gets the type of the hyperlink action. - * Must be a LINK_* constant - * - * @return the hyperlink URL - * @see InteractiveInfoAtom - */ - public int getType() { - return type; - } - - public void setType(int val) { - type = val; - switch(type){ - case LINK_NEXTSLIDE: - title = "NEXT"; - address = "1,-1,NEXT"; - break; - case LINK_PREVIOUSSLIDE: - title = "PREV"; - address = "1,-1,PREV"; - break; - case LINK_FIRSTSLIDE: - title = "FIRST"; - address = "1,-1,FIRST"; - break; - case LINK_LASTSLIDE: - title = "LAST"; - address = "1,-1,LAST"; - break; - case LINK_SLIDENUMBER: - break; - default: - title = ""; - address = ""; - break; - } - } - - /** - * Gets the hyperlink URL - * - * @return the hyperlink URL - */ - public String getAddress() { - return address; - } - - public void setAddress(HSLFSlide slide) { - String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber(); - setAddress(href);; - setTitle("Slide " + slide.getSlideNumber()); - setType(Hyperlink.LINK_SLIDENUMBER); - } - - public void setAddress(String str) { - address = str; - } - - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - /** - * Gets the hyperlink user-friendly title (if different from URL) - * - * @return the hyperlink user-friendly title - */ - public String getTitle() { - return title; - } - - public void setTitle(String str) { - title = str; - } - - /** - * Gets the beginning character position - * - * @return the beginning character position - */ - public int getStartIndex() { - return startIndex; - } - - /** - * Gets the ending character position - * - * @return the ending character position - */ - public int getEndIndex() { - return endIndex; - } - - /** - * Find hyperlinks in a text run - * - * @param run TextRun to lookup hyperlinks in - * @return found hyperlinks or null if not found - */ - protected static Hyperlink[] find(HSLFTextParagraph run){ - List lst = new ArrayList(); - HSLFSlideShow ppt = run.getSheet().getSlideShow(); - //document-level container which stores info about all links in a presentation - ExObjList exobj = ppt.getDocumentRecord().getExObjList(); - if (exobj == null) { - return null; - } - Record[] records = run._records; - if(records != null) find(records, exobj, lst); - - Hyperlink[] links = null; - if (lst.size() > 0){ - links = new Hyperlink[lst.size()]; - lst.toArray(links); - } - return links; - } - - /** - * Find hyperlink assigned to the supplied shape - * - * @param shape Shape to lookup hyperlink in - * @return found hyperlink or null - */ - protected static Hyperlink find(HSLFShape shape){ - List lst = new ArrayList(); - HSLFSlideShow ppt = shape.getSheet().getSlideShow(); - //document-level container which stores info about all links in a presentation - ExObjList exobj = ppt.getDocumentRecord().getExObjList(); - if (exobj == null) { - return null; - } - - EscherContainerRecord spContainer = shape.getSpContainer(); - for (Iterator it = spContainer.getChildIterator(); it.hasNext(); ) { - EscherRecord obj = it.next(); - if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID){ - byte[] data = obj.serialize(); - Record[] records = Record.findChildRecords(data, 8, data.length-8); - if(records != null) find(records, exobj, lst); - } - } - - return lst.size() == 1 ? (Hyperlink)lst.get(0) : null; - } - - private static void find(Record[] records, ExObjList exobj, List out){ - for (int i = 0; i < records.length; i++) { - //see if we have InteractiveInfo in the textrun's records - if( records[i] instanceof InteractiveInfo){ - InteractiveInfo hldr = (InteractiveInfo)records[i]; - InteractiveInfoAtom info = hldr.getInteractiveInfoAtom(); - int id = info.getHyperlinkID(); - ExHyperlink linkRecord = exobj.get(id); - if (linkRecord != null){ - Hyperlink link = new Hyperlink(); - link.title = linkRecord.getLinkTitle(); - link.address = linkRecord.getLinkURL(); - link.type = info.getAction(); - - if (++i < records.length && records[i] instanceof TxInteractiveInfoAtom){ - TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)records[i]; - link.startIndex = txinfo.getStartIndex(); - link.endIndex = txinfo.getEndIndex(); - } - out.add(link); - } - } - } - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Line.java b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java index b2e0b35884..b28c88ec68 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Line.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Line.java @@ -18,6 +18,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeType; @@ -30,7 +31,7 @@ import java.awt.geom.Line2D; * @author Yegor Kozlov */ public final class Line extends HSLFSimpleShape { - protected Line(EscherContainerRecord escherRecord, ShapeContainer parent){ + public Line(EscherContainerRecord escherRecord, ShapeContainer parent){ super(escherRecord, parent); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java index e366fdbe92..27b0000537 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/MovieShape.java @@ -24,7 +24,7 @@ import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherProperties; import org.apache.poi.hslf.exceptions.HSLFException; import org.apache.poi.hslf.record.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeContainer; /** @@ -67,7 +67,7 @@ public final class MovieShape extends HSLFPictureShape { * this picture in the Slide * @param parent the parent shape of this picture */ - protected MovieShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + public MovieShape(EscherContainerRecord escherRecord, ShapeContainer parent){ super(escherRecord, parent); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java index 49ed8c2073..be680bfd81 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/OLEShape.java @@ -18,8 +18,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFObjectData; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hslf.record.ExObjList; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.ExEmbed; @@ -63,7 +62,7 @@ public final class OLEShape extends HSLFPictureShape { * this picture in the Slide * @param parent the parent shape of this picture */ - protected OLEShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + public OLEShape(EscherContainerRecord escherRecord, ShapeContainer parent){ super(escherRecord, parent); } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java index 47500df2f6..526ccc7dc1 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java @@ -19,19 +19,20 @@ package org.apache.poi.hslf.model; import java.awt.*; -import java.awt.Shape; -import java.awt.font.FontRenderContext; -import java.awt.font.GlyphVector; -import java.awt.font.TextLayout; +import java.awt.font.*; +import java.awt.geom.*; import java.awt.image.*; import java.awt.image.renderable.RenderableImage; -import java.awt.geom.*; import java.text.AttributedCharacterIterator; import java.util.Map; -import org.apache.poi.hslf.usermodel.HSLFTextRun; + import org.apache.poi.hslf.exceptions.HSLFException; -import org.apache.poi.util.POILogger; +import org.apache.poi.hslf.usermodel.*; +import org.apache.poi.sl.usermodel.StrokeStyle; +import org.apache.poi.sl.usermodel.VerticalAlignment; +import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; /** * Translates Graphics2D calls into PowerPoint. @@ -251,10 +252,10 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { */ public void drawString(String s, float x, float y) { HSLFTextBox txt = new HSLFTextBox(_group); - txt.getTextParagraph().supplySheet(_group.getSheet()); + txt.getTextParagraphs().get(0).supplySheet(_group.getSheet()); txt.setText(s); - HSLFTextRun rt = txt.getTextParagraph().getRichTextRuns()[0]; + HSLFTextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0); rt.setFontSize(_font.getSize()); rt.setFontName(_font.getFamily()); @@ -262,13 +263,13 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { if (_font.isBold()) rt.setBold(true); if (_font.isItalic()) rt.setItalic(true); - txt.setMarginBottom(0); - txt.setMarginTop(0); - txt.setMarginLeft(0); - txt.setMarginRight(0); + txt.setBottomInset(0); + txt.setTopInset(0); + txt.setLeftInset(0); + txt.setRightInset(0); txt.setWordWrap(HSLFTextBox.WrapNone); - txt.setHorizontalAlignment(HSLFTextBox.AlignLeft); - txt.setVerticalAlignment(HSLFTextBox.AnchorMiddle); + txt.setHorizontalCentered(false); + txt.setVerticalAlignment(VerticalAlignment.MIDDLE); TextLayout layout = new TextLayout(s, _font, getFontRenderContext()); @@ -1794,7 +1795,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { float[] dash = bs.getDashArray(); if (dash != null) { //TODO: implement more dashing styles - shape.setLineDashing(Line.PEN_DASH); + shape.setLineDashing(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 index 470f6a4204..78e7a47350 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Placeholder.java @@ -19,6 +19,8 @@ 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.exceptions.HSLFException; import org.apache.poi.sl.usermodel.ShapeContainer; diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Polygon.java b/src/scratchpad/src/org/apache/poi/hslf/model/Polygon.java index 7bfd95a571..25f93a4e89 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Polygon.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Polygon.java @@ -18,6 +18,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeType; import org.apache.poi.util.LittleEndian; diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java deleted file mode 100644 index d21cf9dd2b..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeFactory.java +++ /dev/null @@ -1,157 +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 java.util.Iterator; -import java.util.List; - -import org.apache.poi.ddf.EscherClientDataRecord; -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherOptRecord; -import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.ddf.EscherProperty; -import org.apache.poi.ddf.EscherPropertyFactory; -import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.ddf.EscherSimpleProperty; -import org.apache.poi.ddf.EscherSpRecord; -import org.apache.poi.hslf.record.InteractiveInfo; -import org.apache.poi.hslf.record.InteractiveInfoAtom; -import org.apache.poi.hslf.record.OEShapeAtom; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.RecordTypes; -import org.apache.poi.sl.usermodel.ShapeContainer; -import org.apache.poi.sl.usermodel.ShapeType; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * Create a Shape object depending on its type - * - * @author Yegor Kozlov - */ -public final class ShapeFactory { - // For logging - protected static final POILogger logger = POILogFactory.getLogger(ShapeFactory.class); - - /** - * Create a new shape from the data provided. - */ - public static HSLFShape createShape(EscherContainerRecord spContainer, ShapeContainer parent){ - if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ - return createShapeGroup(spContainer, parent); - } - return createSimpeShape(spContainer, parent); - } - - public static HSLFGroupShape createShapeGroup(EscherContainerRecord spContainer, ShapeContainer parent){ - HSLFGroupShape group = null; - EscherRecord opt = HSLFShape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122); - if(opt != null){ - try { - EscherPropertyFactory f = new EscherPropertyFactory(); - List props = f.createProperties( opt.serialize(), 8, opt.getInstance() ); - EscherSimpleProperty p = (EscherSimpleProperty)props.get(0); - if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){ - group = new Table(spContainer, parent); - } else { - group = new HSLFGroupShape(spContainer, parent); - } - } catch (Exception e){ - logger.log(POILogger.WARN, e.getMessage()); - group = new HSLFGroupShape(spContainer, parent); - } - } else { - group = new HSLFGroupShape(spContainer, parent); - } - - return group; - } - - public static HSLFShape createSimpeShape(EscherContainerRecord spContainer, ShapeContainer parent){ - HSLFShape shape = null; - EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID); - - ShapeType type = ShapeType.forId(spRecord.getShapeType(), false); - switch (type){ - case TEXT_BOX: - 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); - break; - } - case LINE: - shape = new Line(spContainer, parent); - break; - case NOT_PRIMITIVE: { - EscherOptRecord 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.WARN, "Creating AutoShape for a NotPrimitive shape"); - shape = new HSLFAutoShape(spContainer, parent); - } - break; - } - default: - shape = new HSLFAutoShape(spContainer, parent); - break; - } - return shape; - - } - - @SuppressWarnings("unchecked") - protected static T getClientDataRecord(EscherContainerRecord spContainer, int recordType) { - Record oep = null; - for (Iterator it = spContainer.getChildIterator(); it.hasNext();) { - EscherRecord obj = it.next(); - if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) { - byte[] data = obj.serialize(); - Record[] records = Record.findChildRecords(data, 8, data.length - 8); - for (int j = 0; j < records.length; j++) { - if (records[j].getRecordType() == recordType) { - return (T)records[j]; - } - } - } - } - return (T)oep; - } - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java deleted file mode 100644 index 52e5a86bb1..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeOutline.java +++ /dev/null @@ -1,28 +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; - -/** - * Date: Apr 17, 2008 - * - * @author Yegor Kozlov - */ -public interface ShapeOutline { - java.awt.Shape getOutline(HSLFShape shape); - -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java deleted file mode 100644 index e9686a6120..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapePainter.java +++ /dev/null @@ -1,105 +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 java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Stroke; -import java.awt.geom.Rectangle2D; - -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * Paint a shape into java.awt.Graphics2D - * - * @author Yegor Kozlov - */ -public final class ShapePainter { - protected static final POILogger logger = POILogFactory.getLogger(ShapePainter.class); - - public static void paint(HSLFSimpleShape shape, Graphics2D graphics){ - Rectangle2D anchor = shape.getLogicalAnchor2D(); - java.awt.Shape outline = shape.getOutline(); - - //flip vertical - if(shape.getFlipVertical()){ - graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight()); - graphics.scale(1, -1); - graphics.translate(-anchor.getX(), -anchor.getY()); - } - //flip horizontal - if(shape.getFlipHorizontal()){ - graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY()); - graphics.scale(-1, 1); - graphics.translate(-anchor.getX() , -anchor.getY()); - } - - //rotate transform - double angle = shape.getRotation(); - - if(angle != 0){ - double centerX = anchor.getX() + anchor.getWidth()/2; - double centerY = anchor.getY() + anchor.getHeight()/2; - - graphics.translate(centerX, centerY); - graphics.rotate(Math.toRadians(angle)); - graphics.translate(-centerX, -centerY); - } - - //fill - Color fillColor = shape.getFill().getForegroundColor(); - if (fillColor != null) { - //TODO: implement gradient and texture fill patterns - graphics.setPaint(fillColor); - graphics.fill(outline); - } - - //border - Color lineColor = shape.getLineColor(); - if (lineColor != null){ - graphics.setPaint(lineColor); - float width = (float)shape.getLineWidth(); - - int dashing = shape.getLineDashing(); - //TODO: implement more dashing styles - float[] dashptrn = null; - switch(dashing){ - case Line.PEN_SOLID: - dashptrn = null; - break; - case Line.PEN_PS_DASH: - dashptrn = new float[]{width, width}; - break; - case Line.PEN_DOTGEL: - dashptrn = new float[]{width*4, width*3}; - break; - default: - logger.log(POILogger.WARN, "unsupported dashing: " + dashing); - dashptrn = new float[]{width, width}; - break; - } - - Stroke stroke = new BasicStroke(width, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 10.0f, dashptrn, 0.0f); - graphics.setStroke(stroke); - graphics.draw(outline); - } - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java b/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java deleted file mode 100644 index 859ceebb42..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java +++ /dev/null @@ -1,148 +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.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; -import org.apache.poi.hslf.record.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; - -/** - * SlideMaster determines the graphics, layout, and formatting for all the slides in a given presentation. - * It stores information about default font styles, placeholder sizes and positions, - * background design, and color schemes. - * - * @author Yegor Kozlov - */ -public final class SlideMaster extends HSLFMasterSheet { - private HSLFTextParagraph[] _runs; - - /** - * all TxMasterStyleAtoms available in this master - */ - private TxMasterStyleAtom[] _txmaster; - - /** - * Constructs a SlideMaster from the MainMaster record, - * - */ - public SlideMaster(MainMaster record, int sheetNo) { - super(record, sheetNo); - - _runs = findTextRuns(getPPDrawing()); - for (int i = 0; i < _runs.length; i++) _runs[i].setSheet(this); - } - - /** - * Returns an array of all the TextRuns found - */ - public HSLFTextParagraph[] getTextRuns() { - return _runs; - } - - /** - * Returns null since SlideMasters doen't have master sheet. - */ - public HSLFMasterSheet getMasterSheet() { - return null; - } - - /** - * Pickup a style attribute from the master. - * This is the "workhorse" which returns the default style attrubutes. - */ - public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { - - TextProp prop = null; - for (int i = level; i >= 0; i--) { - TextPropCollection[] styles = - isCharacter ? _txmaster[txtype].getCharacterStyles() : _txmaster[txtype].getParagraphStyles(); - if (i < styles.length) prop = styles[i].findByName(name); - if (prop != null) break; - } - if (prop == null) { - if(isCharacter) { - switch (txtype) { - case TextHeaderAtom.CENTRE_BODY_TYPE: - case TextHeaderAtom.HALF_BODY_TYPE: - case TextHeaderAtom.QUARTER_BODY_TYPE: - txtype = TextHeaderAtom.BODY_TYPE; - break; - case TextHeaderAtom.CENTER_TITLE_TYPE: - txtype = TextHeaderAtom.TITLE_TYPE; - break; - default: - return null; - } - } else { - switch (txtype) { - case TextHeaderAtom.CENTRE_BODY_TYPE: - case TextHeaderAtom.HALF_BODY_TYPE: - case TextHeaderAtom.QUARTER_BODY_TYPE: - txtype = TextHeaderAtom.BODY_TYPE; - break; - case TextHeaderAtom.CENTER_TITLE_TYPE: - txtype = TextHeaderAtom.TITLE_TYPE; - break; - default: - return null; - } - } - prop = getStyleAttribute(txtype, level, name, isCharacter); - } - return prop; - } - - /** - * Assign SlideShow for this slide master. - * (Used interanlly) - */ - public void setSlideShow(HSLFSlideShow ss) { - super.setSlideShow(ss); - - //after the slide show is assigned collect all available style records - if (_txmaster == null) { - _txmaster = new TxMasterStyleAtom[9]; - - TxMasterStyleAtom txdoc = getSlideShow().getDocumentRecord().getEnvironment().getTxMasterStyleAtom(); - _txmaster[txdoc.getTextType()] = txdoc; - - TxMasterStyleAtom[] txrec = ((MainMaster)getSheetContainer()).getTxMasterStyleAtoms(); - for (int i = 0; i < txrec.length; i++) { - int txType = txrec[i].getTextType(); - if(_txmaster[txType] == null) _txmaster[txType] = txrec[i]; - } - } - } - - protected void onAddTextShape(HSLFTextShape shape) { - HSLFTextParagraph run = shape.getTextParagraph(); - - if(_runs == null) _runs = new HSLFTextParagraph[]{run}; - else { - HSLFTextParagraph[] tmp = new HSLFTextParagraph[_runs.length + 1]; - System.arraycopy(_runs, 0, tmp, 0, _runs.length); - tmp[tmp.length-1] = run; - _runs = tmp; - } - } - - public TxMasterStyleAtom[] getTxMasterStyleAtoms(){ - return _txmaster; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Table.java b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java index 99ee13f211..c2cc0ce80b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Table.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java @@ -18,6 +18,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.util.LittleEndian; @@ -319,9 +320,9 @@ public final class Table extends HSLFGroupShape { private Line cloneBorder(Line line){ Line border = createBorder(); border.setLineWidth(line.getLineWidth()); - border.setLineStyle(line.getStrokeStyle()); border.setLineDashing(line.getLineDashing()); border.setLineColor(line.getLineColor()); + border.setLineCompound(line.getLineCompound()); return border; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java index 18431a720c..cfdee76633 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java @@ -22,6 +22,8 @@ import java.awt.Rectangle; import org.apache.poi.ddf.EscherContainerRecord; import org.apache.poi.ddf.EscherOptRecord; import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.hslf.usermodel.HSLFShape; +import org.apache.poi.hslf.usermodel.HSLFTextBox; import org.apache.poi.sl.usermodel.ShapeContainer; import org.apache.poi.sl.usermodel.ShapeType; diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java deleted file mode 100644 index 038e28a04d..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java +++ /dev/null @@ -1,418 +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 java.awt.Color; -import java.awt.Font; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.font.FontRenderContext; -import java.awt.font.LineBreakMeasurer; -import java.awt.font.TextAttribute; -import java.awt.font.TextLayout; -import java.awt.geom.AffineTransform; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.text.AttributedCharacterIterator; -import java.text.AttributedString; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.apache.poi.hslf.record.TextRulerAtom; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.util.POILogFactory; -import org.apache.poi.util.POILogger; - -/** - * Paint text into java.awt.Graphics2D - * - * @author Yegor Kozlov - */ -public final class TextPainter { - public static final Key KEY_FONTFALLBACK = new Key(50, "Font fallback map"); - public static final Key KEY_FONTMAP = new Key(51, "Font map"); - - protected POILogger logger = POILogFactory.getLogger(this.getClass()); - - /** - * Display unicode square if a bullet char can't be displayed, - * for example, if Wingdings font is used. - * TODO: map Wingdngs and Symbol to unicode Arial - */ - protected static final char DEFAULT_BULLET_CHAR = '\u25a0'; - - protected HSLFTextShape _shape; - - public TextPainter(HSLFTextShape shape){ - _shape = shape; - } - - public AttributedString getAttributedString(HSLFTextParagraph txrun) { - return getAttributedString(txrun, null); - } - - /** - * Convert the underlying set of rich text runs into java.text.AttributedString - */ - public AttributedString getAttributedString(HSLFTextParagraph txrun, Graphics2D graphics){ - String text = txrun.getText(); - //TODO: properly process tabs - text = text.replace('\t', ' '); - text = text.replace((char)160, ' '); - - AttributedString at = new AttributedString(text); - HSLFTextRun[] rt = txrun.getRichTextRuns(); - for (int i = 0; i < rt.length; i++) { - int start = rt[i].getStartIndex(); - int end = rt[i].getEndIndex(); - if(start == end) { - logger.log(POILogger.INFO, "Skipping RichTextRun with zero length"); - continue; - } - - String mappedFont = rt[i].getFontName(); - String fallbackFont = Font.SANS_SERIF; - if (graphics != null) { - @SuppressWarnings("unchecked") - Map fontMap = (Map)graphics.getRenderingHint(KEY_FONTMAP); - if (fontMap != null && fontMap.containsKey(mappedFont)) { - mappedFont = fontMap.get(mappedFont); - } - @SuppressWarnings("unchecked") - Map fallbackMap = (Map)graphics.getRenderingHint(KEY_FONTFALLBACK); - if (fallbackMap != null && fallbackMap.containsKey(mappedFont)) { - fallbackFont = fallbackMap.get(mappedFont); - } - } - - at.addAttribute(TextAttribute.FAMILY, mappedFont, start, end); - at.addAttribute(TextAttribute.SIZE, new Float(rt[i].getFontSize()), start, end); - at.addAttribute(TextAttribute.FOREGROUND, rt[i].getFontColor(), start, end); - if(rt[i].isBold()) at.addAttribute(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD, start, end); - if(rt[i].isItalic()) at.addAttribute(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, start, end); - if(rt[i].isUnderlined()) { - at.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, start, end); - at.addAttribute(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, start, end); - } - if(rt[i].isStrikethrough()) at.addAttribute(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH_ON, start, end); - int superScript = rt[i].getSuperscript(); - if(superScript != 0) at.addAttribute(TextAttribute.SUPERSCRIPT, superScript > 0 ? TextAttribute.SUPERSCRIPT_SUPER : TextAttribute.SUPERSCRIPT_SUB, start, end); - - - int style = (rt[i].isBold() ? Font.BOLD : 0) | (rt[i].isItalic() ? Font.ITALIC : 0); - Font f = new Font(mappedFont, style, rt[i].getFontSize()); - - // check for unsupported characters and add a fallback font for these - char textChr[] = text.toCharArray(); - int nextEnd = f.canDisplayUpTo(textChr, start, end); - boolean isNextValid = nextEnd == start; - for (int last = start; nextEnd != -1 && nextEnd <= end; ) { - if (isNextValid) { - nextEnd = f.canDisplayUpTo(textChr, nextEnd, end); - isNextValid = false; - } else { - if (nextEnd >= end || f.canDisplay(Character.codePointAt(textChr, nextEnd, end)) ) { - at.addAttribute(TextAttribute.FAMILY, fallbackFont, last, Math.min(nextEnd,end)); - if (nextEnd >= end) break; - last = nextEnd; - isNextValid = true; - } else { - boolean isHS = Character.isHighSurrogate(textChr[nextEnd]); - nextEnd+=(isHS?2:1); - } - } - } - } - return at; - } - - public void paint(Graphics2D graphics){ - AffineTransform tx = graphics.getTransform(); - - Rectangle2D anchor = _shape.getLogicalAnchor2D(); - TextElement[] elem = getTextElements((float)anchor.getWidth(), graphics.getFontRenderContext(), graphics); - if(elem == null) return; - - float textHeight = 0; - for (int i = 0; i < elem.length; i++) { - textHeight += elem[i].ascent + elem[i].descent; - } - - int valign = _shape.getVerticalAlignment(); - double y0 = anchor.getY(); - switch (valign){ - case HSLFTextShape.AnchorTopBaseline: - case HSLFTextShape.AnchorTop: - y0 += _shape.getMarginTop(); - break; - case HSLFTextShape.AnchorBottom: - y0 += anchor.getHeight() - textHeight - _shape.getMarginBottom(); - break; - default: - case HSLFTextShape.AnchorMiddle: - float delta = (float)anchor.getHeight() - textHeight - _shape.getMarginTop() - _shape.getMarginBottom(); - y0 += _shape.getMarginTop() + delta/2; - break; - } - - - // Transform of text in flipped shapes is special. - // At this point the flip and rotation transform is already applied - // (see XSLFShape#applyTransform ), but we need to restore it to avoid painting "upside down". - // See Bugzilla 54210. - if(_shape.getFlipVertical()){ - graphics.translate(anchor.getX(), anchor.getY() + anchor.getHeight()); - graphics.scale(1, -1); - graphics.translate(-anchor.getX(), -anchor.getY()); - - // text in vertically flipped shapes is rotated by 180 degrees - double centerX = anchor.getX() + anchor.getWidth()/2; - double centerY = anchor.getY() + anchor.getHeight()/2; - graphics.translate(centerX, centerY); - graphics.rotate(Math.toRadians(180)); - graphics.translate(-centerX, -centerY); - } - - // Horizontal flipping applies only to shape outline and not to the text in the shape. - // Applying flip second time restores the original not-flipped transform - if(_shape.getFlipHorizontal()){ - graphics.translate(anchor.getX() + anchor.getWidth(), anchor.getY()); - graphics.scale(-1, 1); - graphics.translate(-anchor.getX() , -anchor.getY()); - } - - //finally draw the text fragments - for (int i = 0; i < elem.length; i++) { - y0 += elem[i].ascent; - - Point2D.Double pen = new Point2D.Double(); - pen.y = y0; - switch (elem[i]._align) { - default: - case HSLFTextShape.AlignLeft: - pen.x = anchor.getX() + _shape.getMarginLeft(); - break; - case HSLFTextShape.AlignCenter: - pen.x = anchor.getX() + _shape.getMarginLeft() + - (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2; - break; - case HSLFTextShape.AlignRight: - pen.x = anchor.getX() + _shape.getMarginLeft() + - (anchor.getWidth() - elem[i].advance - _shape.getMarginLeft() - _shape.getMarginRight()); - break; - } - if(elem[i]._bullet != null){ - graphics.drawString(elem[i]._bullet.getIterator(), (float)(pen.x + elem[i]._bulletOffset), (float)pen.y); - } - AttributedCharacterIterator chIt = elem[i]._text.getIterator(); - if(chIt.getEndIndex() > chIt.getBeginIndex()) { - graphics.drawString(chIt, (float)(pen.x + elem[i]._textOffset), (float)pen.y); - } - y0 += elem[i].descent; - } - - graphics.setTransform(tx); - } - - public TextElement[] getTextElements(float textWidth, FontRenderContext frc){ - return getTextElements(textWidth, frc, null); - } - - public TextElement[] getTextElements(float textWidth, FontRenderContext frc, Graphics2D graphics){ - HSLFTextParagraph run = _shape.getTextParagraph(); - if (run == null) return null; - - String text = run.getText(); - if (text == null || text.equals("")) return null; - - AttributedString at = getAttributedString(run, graphics); - - AttributedCharacterIterator it = at.getIterator(); - int paragraphStart = it.getBeginIndex(); - int paragraphEnd = it.getEndIndex(); - - List lines = new ArrayList(); - LineBreakMeasurer measurer = new LineBreakMeasurer(it, frc); - measurer.setPosition(paragraphStart); - while (measurer.getPosition() < paragraphEnd) { - int startIndex = measurer.getPosition(); - int nextBreak = text.indexOf('\n', measurer.getPosition() + 1); - - boolean prStart = text.charAt(startIndex) == '\n'; - if(prStart) measurer.setPosition(startIndex++); - - HSLFTextRun rt = run.getRichTextRunAt(startIndex == text.length() ? (startIndex-1) : startIndex); - if(rt == null) { - logger.log(POILogger.WARN, "RichTextRun not found at pos" + startIndex + "; text.length: " + text.length()); - break; - } - - float wrappingWidth = textWidth - _shape.getMarginLeft() - _shape.getMarginRight(); - int bulletOffset = rt.getBulletOffset(); - int textOffset = rt.getTextOffset(); - int indent = rt.getIndentLevel(); - - TextRulerAtom ruler = run.getTextRuler(); - if(ruler != null) { - int bullet_val = ruler.getBulletOffsets()[indent]*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - int text_val = ruler.getTextOffsets()[indent]*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - if(bullet_val > text_val){ - int a = bullet_val; - bullet_val = text_val; - text_val = a; - } - if(bullet_val != 0 ) bulletOffset = bullet_val; - if(text_val != 0) textOffset = text_val; - } - - if(bulletOffset > 0 || prStart || startIndex == 0) wrappingWidth -= textOffset; - - if (_shape.getWordWrap() == HSLFTextShape.WrapNone) { - wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width; - } - - TextLayout textLayout = measurer.nextLayout(wrappingWidth + 1, - nextBreak == -1 ? paragraphEnd : nextBreak, true); - if (textLayout == null) { - textLayout = measurer.nextLayout(textWidth, - nextBreak == -1 ? paragraphEnd : nextBreak, false); - } - if(textLayout == null){ - logger.log(POILogger.WARN, "Failed to break text into lines: wrappingWidth: "+wrappingWidth+ - "; text: " + rt.getText()); - measurer.setPosition(rt.getEndIndex()); - continue; - } - int endIndex = measurer.getPosition(); - - float lineHeight = (float)textLayout.getBounds().getHeight(); - int linespacing = rt.getLineSpacing(); - if(linespacing == 0) linespacing = 100; - - TextElement el = new TextElement(); - if(linespacing >= 0){ - el.ascent = textLayout.getAscent()*linespacing/100; - } else { - el.ascent = -linespacing*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - - el._align = rt.getAlignment(); - el.advance = textLayout.getAdvance(); - el._textOffset = textOffset; - el._text = new AttributedString(it, startIndex, endIndex); - el.textStartIndex = startIndex; - el.textEndIndex = endIndex; - - if (prStart){ - int sp = rt.getSpaceBefore(); - float spaceBefore; - if(sp >= 0){ - spaceBefore = lineHeight * sp/100; - } else { - spaceBefore = -sp*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - el.ascent += spaceBefore; - } - - float descent; - if(linespacing >= 0){ - descent = (textLayout.getDescent() + textLayout.getLeading())*linespacing/100; - } else { - descent = -linespacing*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - if (prStart){ - int sp = rt.getSpaceAfter(); - float spaceAfter; - if(sp >= 0){ - spaceAfter = lineHeight * sp/100; - } else { - spaceAfter = -sp*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - el.ascent += spaceAfter; - } - el.descent = descent; - - if(rt.isBullet() && (prStart || startIndex == 0)){ - it.setIndex(startIndex); - - AttributedString bat = new AttributedString(Character.toString(rt.getBulletChar())); - Color clr = rt.getBulletColor(); - if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr); - else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND)); - - int fontIdx = rt.getBulletFont(); - if(fontIdx == -1) fontIdx = rt.getFontIndex(); - PPFont bulletFont = _shape.getSheet().getSlideShow().getFont(fontIdx); - bat.addAttribute(TextAttribute.FAMILY, bulletFont.getFontName()); - - int bulletSize = rt.getBulletSize(); - int fontSize = rt.getFontSize(); - if(bulletSize != -1) fontSize = Math.round(fontSize*bulletSize*0.01f); - bat.addAttribute(TextAttribute.SIZE, new Float(fontSize)); - - if(!new Font(bulletFont.getFontName(), Font.PLAIN, 1).canDisplay(rt.getBulletChar())){ - bat.addAttribute(TextAttribute.FAMILY, "Arial"); - bat = new AttributedString("" + DEFAULT_BULLET_CHAR, bat.getIterator().getAttributes()); - } - - if(text.substring(startIndex, endIndex).length() > 1){ - el._bullet = bat; - el._bulletOffset = bulletOffset; - } - } - lines.add(el); - } - - //finally draw the text fragments - TextElement[] elems = new TextElement[lines.size()]; - return lines.toArray(elems); - } - - public static class TextElement { - public AttributedString _text; - public int _textOffset; - public AttributedString _bullet; - public int _bulletOffset; - public int _align; - public float ascent, descent; - public float advance; - public int textStartIndex, textEndIndex; - } - - public static class Key extends RenderingHints.Key { - String description; - - public Key(int paramInt, String paramString) { - super(paramInt); - this.description = paramString; - } - - public final int getIndex() { - return intKey(); - } - - public final String toString() { - return this.description; - } - - public boolean isCompatibleValue(Object paramObject) { - return true; - } - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TitleMaster.java b/src/scratchpad/src/org/apache/poi/hslf/model/TitleMaster.java deleted file mode 100644 index 8184c030fa..0000000000 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TitleMaster.java +++ /dev/null @@ -1,69 +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.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.record.*; - -/** - * Title masters define the design template for slides with a Title Slide layout. - * - * @author Yegor Kozlov - */ -public final class TitleMaster extends HSLFMasterSheet { - private HSLFTextParagraph[] _runs; - - /** - * Constructs a TitleMaster - * - */ - public TitleMaster(org.apache.poi.hslf.record.Slide record, int sheetNo) { - super(record, sheetNo); - - _runs = findTextRuns(getPPDrawing()); - for (int i = 0; i < _runs.length; i++) _runs[i].setSheet(this); - } - - /** - * Returns an array of all the TextRuns found - */ - public HSLFTextParagraph[] getTextRuns() { - return _runs; - } - - /** - * Delegate the call to the underlying slide master. - */ - public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { - HSLFMasterSheet master = getMasterSheet(); - return master == null ? null : master.getStyleAttribute(txtype, level, name, isCharacter); - } - - /** - * Returns the slide master for this title master. - */ - public HSLFMasterSheet getMasterSheet(){ - SlideMaster[] master = getSlideShow().getSlidesMasters(); - SlideAtom sa = ((org.apache.poi.hslf.record.Slide)getSheetContainer()).getSlideAtom(); - int masterId = sa.getMasterID(); - for (int i = 0; i < master.length; i++) { - if (masterId == master[i]._getSheetNumber()) return master[i]; - } - return null; - } -} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java index cf25eb6cd1..0f8bab418c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/BitMaskTextProp.java @@ -24,7 +24,7 @@ package org.apache.poi.hslf.model.textproperties; * of the property is itself a mask, encoding several different * (but related) properties */ -public class BitMaskTextProp extends TextProp implements Cloneable { +public abstract class BitMaskTextProp extends TextProp implements Cloneable { private String[] subPropNames; private int[] subPropMasks; private boolean[] subPropMatches; @@ -91,7 +91,8 @@ public class BitMaskTextProp extends TextProp implements Cloneable { subPropMatches[idx] = value; } - public Object clone(){ + @Override + public BitMaskTextProp clone(){ BitMaskTextProp newObj = (BitMaskTextProp)super.clone(); // Don't carry over matches, but keep everything diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/IndentProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/IndentProp.java index 662833203f..40adf46d8f 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/IndentProp.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/IndentProp.java @@ -41,7 +41,7 @@ public class IndentProp { public int getCharactersCovered() { return charactersCovered; } public int getIndentLevel() { - return (int)indentLevel; + return indentLevel; } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TabStopPropCollection.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TabStopPropCollection.java new file mode 100644 index 0000000000..786b373382 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TabStopPropCollection.java @@ -0,0 +1,113 @@ +/* ==================================================================== + 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.textproperties; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.LittleEndianConsts; + +/** + * Container for tabstop lists + */ +public class TabStopPropCollection extends TextProp { + public enum TabStopType { + LEFT(0), CENTER(1), RIGHT(2), DECIMAL(3); + private final int val; + TabStopType(int val) { + this.val = val; + } + public static TabStopType fromRecordVal(int val) { + for (TabStopType tst : values()) { + if (tst.val == val) return tst; + } + return LEFT; + } + } + + public static class TabStop { + /** + * If the TextPFException record that contains this TabStop structure also contains a + * leftMargin, then the value of position is relative to the left margin of the paragraph; + * otherwise, the value is relative to the left side of the paragraph. + * + * If a TextRuler record contains this TabStop structure, the value is relative to the + * left side of the text ruler. + */ + private int position; + + /** + * A enumeration that specifies how text aligns at the tab stop. + */ + private TabStopType type; + + public TabStop(int position, TabStopType type) { + this.position = position; + this.type = type; + } + + public int getPosition() { + return position; + } + + public void setPosition(int position) { + this.position = position; + } + + public TabStopType getType() { + return type; + } + + public void setType(TabStopType type) { + this.type = type; + } + } + + private List tabStops = new ArrayList(); + + public TabStopPropCollection() { + super(0, 0x100000, "tabStops"); + } + + /** + * Parses the tabstops from TxMasterStyle record + * + * @param data the data stream + * @param offset the offset within the data + * @return the new offset + */ + public void parseProperty(byte data[], int offset) { + int count = LittleEndian.getUShort(data, offset); + offset += LittleEndianConsts.SHORT_SIZE; + for (int i=0; i textPropList; + private List textPropList; private int maskSpecial = 0; public int getSpecialMask() { return maskSpecial; } @@ -41,7 +41,7 @@ public class TextPropCollection { /** Fetch the number of characters this styling applies to */ public int getCharactersCovered() { return charactersCovered; } /** Fetch the TextProps that define this styling */ - public LinkedList getTextPropList() { return textPropList; } + public List getTextPropList() { return textPropList; } /** Fetch the TextProp with this name, or null if it isn't present */ public TextProp findByName(String textPropName) { @@ -73,7 +73,7 @@ public class TextPropCollection { } // Add a copy of this property, in the right place to the list - TextProp textProp = (TextProp)base.clone(); + TextProp textProp = base.clone(); int pos = 0; for(int i=0; i= data.length) { // Out of data, can't be any more properties to go // remember the mask and return - maskSpecial |= potentialProperties[i].getMask(); + maskSpecial |= tp.getMask(); return bytesPassed; } // Bingo, data contains this property - TextProp prop = (TextProp)potentialProperties[i].clone(); + TextProp prop = tp.clone(); int val = 0; - if(prop.getSize() == 2) { + if (prop instanceof TabStopPropCollection) { + ((TabStopPropCollection)prop).parseProperty(data, dataOffset+bytesPassed); + } else if (prop.getSize() == 2) { val = LittleEndian.getShort(data,dataOffset+bytesPassed); - } else if(prop.getSize() == 4){ + } else if(prop.getSize() == 4) { val = LittleEndian.getInt(data,dataOffset+bytesPassed); - } else if (prop.getSize() == 0){ + } else if (prop.getSize() == 0) { //remember "special" bits. - maskSpecial |= potentialProperties[i].getMask(); + maskSpecial |= tp.getMask(); continue; } prop.setValue(val); @@ -137,7 +139,7 @@ public class TextPropCollection { public TextPropCollection(int charactersCovered, short reservedField) { this.charactersCovered = charactersCovered; this.reservedField = reservedField; - textPropList = new LinkedList(); + textPropList = new ArrayList(); } /** @@ -147,7 +149,27 @@ public class TextPropCollection { public TextPropCollection(int textSize) { charactersCovered = textSize; reservedField = -1; - textPropList = new LinkedList(); + textPropList = new ArrayList(); + } + + /** + * Clones the given text properties + */ + public void copy(TextPropCollection other) { + this.charactersCovered = other.charactersCovered; + this.reservedField = other.reservedField; + this.textPropList.clear(); + for (TextProp tp : other.textPropList) { + TextProp tpCopy = tp.clone(); + if (tpCopy instanceof BitMaskTextProp) { + BitMaskTextProp bmt = (BitMaskTextProp)tpCopy; + boolean matches[] = ((BitMaskTextProp)tp).getSubPropMatches(); + for (int i=0; i m = new HashMap(); + for (TextProp tp : o.textPropList) { + m.put(tp.getName(), tp); + } + + for (TextProp tp : this.textPropList) { + TextProp otp = m.get(tp.getName()); + if (!tp.equals(otp)) return false; + } + + return true; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java index 3d99e0a716..a306058341 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java @@ -273,8 +273,8 @@ public final class RecordTypes { * offers methods to get either back out. */ public static class Type { - public int typeID; - public Class handlingClass; + public final int typeID; + public final Class handlingClass; public Type(int typeID, Class handlingClass) { this.typeID = typeID; this.handlingClass = handlingClass; diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java index 5730021c90..4e0654a8a6 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java @@ -22,11 +22,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.LinkedList; -import org.apache.poi.hslf.model.textproperties.AlignmentTextProp; -import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.model.textproperties.*; import org.apache.poi.util.HexDump; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogger; @@ -51,7 +47,7 @@ import org.apache.poi.util.POILogger; public final class StyleTextPropAtom extends RecordAtom { private byte[] _header; - private static long _type = 4001l; + private static final long _type = RecordTypes.StyleTextPropAtom.typeID; private byte[] reserved; private byte[] rawContents; // Holds the contents between write-outs @@ -118,7 +114,9 @@ public final class StyleTextPropAtom extends RecordAtom } /** All the different kinds of paragraph properties we might handle */ - public static final TextProp[] paragraphTextPropTypes = new TextProp[] { + public static final TextProp[] paragraphTextPropTypes = { + // TextProp order is according to 2.9.20 TextPFException, + // bitmask order can be different new TextProp(0, 0x1, "hasBullet"), new TextProp(0, 0x2, "hasBulletFont"), new TextProp(0, 0x4, "hasBulletColor"), @@ -129,16 +127,22 @@ public final class StyleTextPropAtom extends RecordAtom new TextProp(2, 0x40, "bullet.size"), new TextProp(4, 0x20, "bullet.color"), new AlignmentTextProp(), - new TextProp(2, 0x100, "text.offset"), - new TextProp(2, 0x400, "bullet.offset"), new TextProp(2, 0x1000, "linespacing"), new TextProp(2, 0x2000, "spacebefore"), new TextProp(2, 0x4000, "spaceafter"), + new TextProp(2, 0x100, "text.offset"), // left margin + // 0x200 - Undefined and MUST be ignored + new TextProp(2, 0x400, "bullet.offset"), // indent new TextProp(2, 0x8000, "defaultTabSize"), - new TextProp(2, 0x100000, "tabStops"), + new TabStopPropCollection(), // tabstops size is variable! new TextProp(2, 0x10000, "fontAlign"), - new TextProp(2, 0xA0000, "wrapFlags"), - new TextProp(2, 0x200000, "textDirection") + new TextProp(2, 0xE0000, "wrapFlags"), // charWrap | wordWrap | overflow + new TextProp(2, 0x200000, "textDirection"), + // 0x400000 MUST be zero and MUST be ignored + new TextProp(0, 0x800000, "bullet.blip"), // TODO: check size + new TextProp(0, 0x1000000, "bullet.scheme"), // TODO: check size + new TextProp(0, 0x2000000, "hasBulletScheme"), // TODO: check size + // 0xFC000000 MUST be zero and MUST be ignored }; /** All the different kinds of character properties we might handle */ public static final TextProp[] characterTextPropTypes = new TextProp[] { @@ -391,6 +395,14 @@ public final class StyleTextPropAtom extends RecordAtom initialised = false; } + /** + * Clear styles, so new collections can be added + */ + public void clearStyles() { + paragraphStyles.clear(); + charStyles.clear(); + } + /** * Create a new Paragraph TextPropCollection, and add it to the list * @param charactersCovered The number of characters this TextPropCollection will cover diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java index b793613764..a576146d09 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextBytesAtom.java @@ -35,7 +35,7 @@ import java.io.OutputStream; public final class TextBytesAtom extends RecordAtom { private byte[] _header; - private static long _type = 4008l; + private static long _type = RecordTypes.TextBytesAtom.typeID; /** The bytes that make up the text */ private byte[] _text; diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextCharsAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextCharsAtom.java index e279af060d..3449250ada 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TextCharsAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextCharsAtom.java @@ -33,7 +33,7 @@ import java.io.OutputStream; public final class TextCharsAtom extends RecordAtom { private byte[] _header; - private static long _type = 4000l; + private static long _type = RecordTypes.TextCharsAtom.typeID; /** The bytes that make up the text */ private byte[] _text; diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java index d19a6c1c01..a63d8934d5 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java @@ -32,7 +32,7 @@ import java.io.OutputStream; public final class TextHeaderAtom extends RecordAtom implements ParentAwareRecord { private byte[] _header; - private static long _type = 3999l; + private static long _type = RecordTypes.TextHeaderAtom.typeID; private RecordContainer parentRecord; public static final int TITLE_TYPE = 0; @@ -46,9 +46,21 @@ public final class TextHeaderAtom extends RecordAtom implements ParentAwareRecor /** The kind of text it is */ private int textType; + /** position in the owning SlideListWithText */ + private int index = -1; public int getTextType() { return textType; } public void setTextType(int type) { textType = type; } + + /** + * @return 0-based index of the text run in the SLWT container + */ + public int getIndex() { return index; } + + /** + * @param id 0-based index of the text run in the SLWT container + */ + public void setIndex(int index) { this.index = index; } public RecordContainer getParentRecord() { return parentRecord; } public void setParentRecord(RecordContainer record) { this.parentRecord = record; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java index f1452bcf58..a3624678a0 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextSpecInfoAtom.java @@ -30,6 +30,8 @@ import java.util.ArrayList; * @author Yegor Kozlov */ public final class TextSpecInfoAtom extends RecordAtom { + private static final long _type = RecordTypes.TextSpecInfoAtom.typeID; + /** * Record header. */ @@ -62,7 +64,7 @@ public final class TextSpecInfoAtom extends RecordAtom { * Gets the record type. * @return the record type. */ - public long getRecordType() { return RecordTypes.TextSpecInfoAtom.typeID; } + public long getRecordType() { return _type; } /** * Write the contents of the record back, so it can be written diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java index 966c8eb8e3..4037d11e44 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java @@ -48,6 +48,37 @@ public final class TxMasterStyleAtom extends RecordAtom { */ public static final int MAX_INDENT = 5; +/* + private static TextProp paragraphSpecialPropTypes[] = { + new ParagraphFlagsTextProp(), + new TextProp(2, 0x80, "bullet.char"), + new TextProp(2, 0x10, "bullet.font"), + new TextProp(2, 0x40, "bullet.size"), + new TextProp(4, 0x20, "bullet.color"), + new TextProp(2, 0xD00, "alignment"), + new TextProp(2, 0x1000, "linespacing"), + new TextProp(2, 0x2000, "spacebefore"), + new TextProp(2, 0x4000, "spaceafter"), + new TextProp(2, 0x8000, "text.offset"), + new TextProp(2, 0x10000, "bullet.offset"), + new TextProp(2, 0x20000, "defaulttab"), + new TextProp(2, 0x40000, "para_unknown_2"), + new TextProp(2, 0x80000, "para_unknown_3"), + new TextProp(2, 0x100000, "para_unknown_4"), + new TextProp(2, 0x200000, "para_unknown_5") + }; + + private static TextProp characterSpecialPropTypes[] = { + new CharFlagsTextProp(), + new TextProp(2, 0x10000, "font.index"), + new TextProp(2, 0x20000, "char_unknown_1"), + new TextProp(4, 0x40000, "char_unknown_2"), + new TextProp(2, 0x80000, "font.size"), + new TextProp(2, 0x100000, "char_unknown_3"), + new TextProp(4, 0x200000, "font.color"), + new TextProp(2, 0x800000, "char_unknown_4") + }; +*/ private byte[] _header; private static long _type = 4003; private byte[] _data; @@ -126,6 +157,7 @@ public final class TxMasterStyleAtom extends RecordAtom { /** * parse the record data and initialize styles */ + @SuppressWarnings("unused") protected void init(){ //type of the text int type = getTextType(); @@ -170,28 +202,10 @@ public final class TxMasterStyleAtom extends RecordAtom { * ones, or the standard StyleTextPropAtom ones */ protected TextProp[] getParagraphProps(int type, int level){ - if (level != 0 || type >= MAX_INDENT){ - return StyleTextPropAtom.paragraphTextPropTypes; - } - return new TextProp[] { - new ParagraphFlagsTextProp(), - new TextProp(2, 0x80, "bullet.char"), - new TextProp(2, 0x10, "bullet.font"), - new TextProp(2, 0x40, "bullet.size"), - new TextProp(4, 0x20, "bullet.color"), - new TextProp(2, 0xD00, "alignment"), - new TextProp(2, 0x1000, "linespacing"), - new TextProp(2, 0x2000, "spacebefore"), - new TextProp(2, 0x4000, "spaceafter"), - new TextProp(2, 0x8000, "text.offset"), - new TextProp(2, 0x10000, "bullet.offset"), - new TextProp(2, 0x20000, "defaulttab"), - new TextProp(2, 0x40000, "para_unknown_2"), - new TextProp(2, 0x80000, "para_unknown_3"), - new TextProp(2, 0x100000, "para_unknown_4"), - new TextProp(2, 0x200000, "para_unknown_5") - }; - + return StyleTextPropAtom.paragraphTextPropTypes; +// return (level != 0 || type >= MAX_INDENT) +// ? StyleTextPropAtom.paragraphTextPropTypes +// : paragraphSpecialPropTypes; } /** @@ -201,18 +215,9 @@ public final class TxMasterStyleAtom extends RecordAtom { * ones, or the standard StyleTextPropAtom ones */ protected TextProp[] getCharacterProps(int type, int level){ - if (level != 0 || type >= MAX_INDENT){ - return StyleTextPropAtom.characterTextPropTypes; - } - return new TextProp[] { - new CharFlagsTextProp(), - new TextProp(2, 0x10000, "font.index"), - new TextProp(2, 0x20000, "char_unknown_1"), - new TextProp(4, 0x40000, "char_unknown_2"), - new TextProp(2, 0x80000, "font.size"), - new TextProp(2, 0x100000, "char_unknown_3"), - new TextProp(4, 0x200000, "font.color"), - new TextProp(2, 0x800000, "char_unknown_4") - }; + return StyleTextPropAtom.characterTextPropTypes; +// return (level != 0 || type >= MAX_INDENT) +// ? StyleTextPropAtom.characterTextPropTypes +// : characterSpecialPropTypes; } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java new file mode 100644 index 0000000000..ceb655250c --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFAutoShape.java @@ -0,0 +1,108 @@ +/* ==================================================================== + 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.ddf.EscherProperties; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.ss.usermodel.ShapeTypes; + +/** + * Represents an AutoShape. + *

    + * AutoShapes are drawing objects with a particular shape that may be customized through smart resizing and adjustments. + * See {@link ShapeTypes} + *

    + * + * @author Yegor Kozlov + */ +public class HSLFAutoShape extends HSLFTextShape implements AutoShape { + + protected HSLFAutoShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + } + + public HSLFAutoShape(ShapeType type, ShapeContainer parent){ + super(null, parent); + _escherContainer = createSpContainer(type, parent instanceof HSLFGroupShape); + } + + public HSLFAutoShape(ShapeType type){ + this(type, null); + } + + protected EscherContainerRecord createSpContainer(ShapeType shapeType, boolean isChild){ + _escherContainer = super.createSpContainer(isChild); + + setShapeType(shapeType); + + //set default properties for an autoshape + setEscherProperty(EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000); + setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); + setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); + setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000); + setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100010); + setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001); + setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80008); + setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); + + return _escherContainer; + } + + protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ + setVerticalAlignment(VerticalAlignment.MIDDLE); + setHorizontalCentered(true); + setWordWrap(HSLFTextBox.WrapNone); + } + + /** + * Gets adjust value which controls smart resizing of the auto-shape. + * + *

    + * The adjustment values are given in shape coordinates: + * the origin is at the top-left, positive-x is to the right, positive-y is down. + * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant). + *

    + * + * @param idx the adjust index in the [0, 9] range + * @return the adjustment value + */ + public int getAdjustmentValue(int idx){ + if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range"); + + return getEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx)); + } + + /** + * Sets adjust value which controls smart resizing of the auto-shape. + * + *

    + * The adjustment values are given in shape coordinates: + * the origin is at the top-left, positive-x is to the right, positive-y is down. + * The region from (0,0) to (S,S) maps to the geometry box of the shape (S=21600 is a constant). + *

    + * + * @param idx the adjust index in the [0, 9] range + * @param val the adjustment value + */ + public void setAdjustmentValue(int idx, int val){ + if(idx < 0 || idx > 9) throw new IllegalArgumentException("The index of an adjustment value must be in the [0, 9] range"); + + setEscherProperty((short)(EscherProperties.GEOMETRY__ADJUSTVALUE + idx), val); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFBackground.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFBackground.java new file mode 100644 index 0000000000..4b9846fd69 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFBackground.java @@ -0,0 +1,38 @@ +/* ==================================================================== + 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.Background; +import org.apache.poi.sl.usermodel.ShapeContainer; + +/** + * Background shape + * + * @author Yegor Kozlov + */ +public final class HSLFBackground extends HSLFShape implements Background { + + protected HSLFBackground(EscherContainerRecord escherRecord, ShapeContainer parent) { + super(escherRecord, parent); + } + + protected EscherContainerRecord createSpContainer(boolean isChild) { + return null; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java new file mode 100644 index 0000000000..9b74711fc6 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFill.java @@ -0,0 +1,310 @@ +/* ==================================================================== + 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 java.awt.Color; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.List; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.record.Document; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; +import org.apache.poi.sl.usermodel.PaintStyle.TexturePaint; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * Represents functionality provided by the 'Fill Effects' dialog in PowerPoint. + * + * @author Yegor Kozlov + */ +public final class HSLFFill { + // For logging + protected POILogger logger = POILogFactory.getLogger(this.getClass()); + + /** + * Fill with a solid color + */ + public static final int FILL_SOLID = 0; + + /** + * Fill with a pattern (bitmap) + */ + public static final int FILL_PATTERN = 1; + + /** + * A texture (pattern with its own color map) + */ + public static final int FILL_TEXTURE = 2; + + /** + * Center a picture in the shape + */ + public static final int FILL_PICTURE = 3; + + /** + * Shade from start to end points + */ + public static final int FILL_SHADE = 4; + + /** + * Shade from bounding rectangle to end point + */ + public static final int FILL_SHADE_CENTER = 5; + + /** + * Shade from shape outline to end point + */ + public static final int FILL_SHADE_SHAPE = 6; + + /** + * Similar to FILL_SHADE, but the fill angle + * is additionally scaled by the aspect ratio of + * the shape. If shape is square, it is the same as FILL_SHADE + */ + public static final int FILL_SHADE_SCALE = 7; + + /** + * shade to title + */ + public static final int FILL_SHADE_TITLE = 8; + + /** + * Use the background fill color/pattern + */ + public static final int FILL_BACKGROUND = 9; + + + + /** + * The shape this background applies to + */ + protected HSLFShape shape; + + /** + * Construct a Fill object for a shape. + * Fill information will be read from shape's escher properties. + * + * @param shape the shape this background applies to + */ + public HSLFFill(HSLFShape shape){ + this.shape = shape; + } + + + public FillStyle getFillStyle() { + return new FillStyle() { + public PaintStyle getPaint() { + switch (getFillType()) { + case FILL_SOLID: { + return new SolidPaint() { + public ColorStyle getSolidColor() { + return new ColorStyle() { + public Color getColor() { return getForegroundColor(); } + public int getAlpha() { return -1; } + public int getLumOff() { return -1; } + public int getLumMod() { return -1; } + public int getShade() { return -1; } + public int getTint() { return -1; } + }; + } + }; + } + case FILL_PICTURE: { + return new TexturePaint() { + final HSLFPictureData pd = getPictureData(); + + public InputStream getImageData() { + return new ByteArrayInputStream(pd.getData()); + } + + public String getContentType() { + return pd.getContentType(); + } + + public int getAlpha() { + return (int)(shape.getAlpha(EscherProperties.FILL__FILLOPACITY)*100000.0); + } + }; + } + default: + logger.log(POILogger.WARN, "unsuported fill type: " + getFillType()); + break; + } + return PaintStyle.TRANSPARENT_PAINT; + } + }; + } + + /** + * Returns fill type. + * Must be one of the FILL_* constants defined in this class. + * + * @return type of fill + */ + public int getFillType(){ + EscherOptRecord opt = shape.getEscherOptRecord(); + EscherSimpleProperty prop = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__FILLTYPE); + return prop == null ? FILL_SOLID : prop.getPropertyValue(); + } + + /** + */ + protected void afterInsert(HSLFSheet sh){ + EscherOptRecord opt = shape.getEscherOptRecord(); + EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE); + if(p != null) { + int idx = p.getPropertyValue(); + EscherBSERecord bse = getEscherBSERecord(idx); + bse.setRef(bse.getRef() + 1); + } + } + + protected EscherBSERecord getEscherBSERecord(int idx){ + HSLFSheet sheet = shape.getSheet(); + if(sheet == null) { + logger.log(POILogger.DEBUG, "Fill has not yet been assigned to a sheet"); + return null; + } + HSLFSlideShow ppt = sheet.getSlideShow(); + Document doc = ppt.getDocumentRecord(); + EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); + EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); + if(bstore == null) { + logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found "); + return null; + } + List lst = bstore.getChildRecords(); + return (EscherBSERecord)lst.get(idx-1); + } + + /** + * Sets fill type. + * Must be one of the FILL_* constants defined in this class. + * + * @param type type of the fill + */ + public void setFillType(int type){ + EscherOptRecord opt = shape.getEscherOptRecord(); + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLTYPE, type); + } + + /** + * Foreground color + */ + public Color getForegroundColor(){ + EscherOptRecord opt = shape.getEscherOptRecord(); + EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); + + if(p != null && (p.getPropertyValue() & 0x10) == 0) return null; + + return shape.getColor(EscherProperties.FILL__FILLCOLOR, EscherProperties.FILL__FILLOPACITY, -1); + + } + + /** + * Foreground color + */ + public void setForegroundColor(Color color){ + EscherOptRecord opt = shape.getEscherOptRecord(); + if (color == null) { + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150000); + } + else { + int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb); + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011); + } + } + + /** + * Background color + */ + public Color getBackgroundColor(){ + EscherOptRecord opt = shape.getEscherOptRecord(); + EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST); + + if(p != null && (p.getPropertyValue() & 0x10) == 0) return null; + + return shape.getColor(EscherProperties.FILL__FILLBACKCOLOR, EscherProperties.FILL__FILLOPACITY, -1); + } + + /** + * Background color + */ + public void setBackgroundColor(Color color){ + EscherOptRecord opt = shape.getEscherOptRecord(); + if (color == null) { + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, -1); + } + else { + int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); + HSLFShape.setEscherProperty(opt, EscherProperties.FILL__FILLBACKCOLOR, rgb); + } + } + + /** + * PictureData object used in a texture, pattern of picture fill. + */ + public HSLFPictureData getPictureData(){ + EscherOptRecord opt = shape.getEscherOptRecord(); + EscherSimpleProperty p = HSLFShape.getEscherProperty(opt, EscherProperties.FILL__PATTERNTEXTURE); + if (p == null) return null; + + HSLFSlideShow ppt = shape.getSheet().getSlideShow(); + HSLFPictureData[] pict = ppt.getPictureData(); + Document doc = ppt.getDocumentRecord(); + + EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); + EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); + + java.util.List lst = bstore.getChildRecords(); + int idx = p.getPropertyValue(); + if (idx == 0){ + logger.log(POILogger.WARN, "no reference to picture data found "); + } else { + EscherBSERecord bse = (EscherBSERecord)lst.get(idx - 1); + for ( int i = 0; i < pict.length; i++ ) { + if (pict[i].getOffset() == bse.getOffset()){ + return pict[i]; + } + } + } + + return null; + } + + /** + * Assign picture used to fill the underlying shape. + * + * @param idx 0-based index of the picture added to this ppt by SlideShow.addPicture method. + */ + public void setPictureData(int idx){ + EscherOptRecord opt = shape.getEscherOptRecord(); + HSLFShape.setEscherProperty(opt, (short)(EscherProperties.FILL__PATTERNTEXTURE + 0x4000), idx); + if( idx != 0 ) { + if( shape.getSheet() != null ) { + EscherBSERecord bse = getEscherBSERecord(idx); + bse.setRef(bse.getRef() + 1); + } + } + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java new file mode 100644 index 0000000000..5128b55307 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFFreeformShape.java @@ -0,0 +1,264 @@ +/* ==================================================================== + 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 java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +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.EscherSimpleProperty; +import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogger; + +/** + * A "Freeform" shape. + * + *

    + * Shapes drawn with the "Freeform" tool have cubic bezier curve segments in the smooth sections + * and straight-line segments in the straight sections. This object closely corresponds to java.awt.geom.GeneralPath. + *

    + * @author Yegor Kozlov + */ +public final class HSLFFreeformShape extends HSLFAutoShape { + + public static final byte[] SEGMENTINFO_MOVETO = new byte[]{0x00, 0x40}; + public static final byte[] SEGMENTINFO_LINETO = new byte[]{0x00, (byte)0xAC}; + public static final byte[] SEGMENTINFO_ESCAPE = new byte[]{0x01, 0x00}; + public static final byte[] SEGMENTINFO_ESCAPE2 = new byte[]{0x01, 0x20}; + public static final byte[] SEGMENTINFO_CUBICTO = new byte[]{0x00, (byte)0xAD}; + public static final byte[] SEGMENTINFO_CUBICTO2 = new byte[]{0x00, (byte)0xB3}; //OpenOffice inserts 0xB3 instead of 0xAD. + public static final byte[] SEGMENTINFO_CLOSE = new byte[]{0x01, (byte)0x60}; + public static final byte[] SEGMENTINFO_END = new byte[]{0x00, (byte)0x80}; + + /** + * Create a Freeform object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected HSLFFreeformShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + + } + + /** + * Create a new Freeform. This constructor is used when a new shape is created. + * + * @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 HSLFFreeformShape(ShapeContainer parent){ + super((EscherContainerRecord)null, parent); + _escherContainer = createSpContainer(ShapeType.NOT_PRIMITIVE, parent instanceof HSLFGroupShape); + } + + /** + * Create a new Freeform. This constructor is used when a new shape is created. + * + */ + public HSLFFreeformShape(){ + this(null); + } + + /** + * Set the shape path + * + * @param path + */ + public void setPath(GeneralPath path) + { + Rectangle2D bounds = path.getBounds2D(); + PathIterator it = path.getPathIterator(new AffineTransform()); + + List segInfo = new ArrayList(); + List pntInfo = new ArrayList(); + boolean isClosed = false; + while (!it.isDone()) { + double[] vals = new double[6]; + int type = it.currentSegment(vals); + switch (type) { + case PathIterator.SEG_MOVETO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + segInfo.add(SEGMENTINFO_MOVETO); + break; + case PathIterator.SEG_LINETO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + segInfo.add(SEGMENTINFO_LINETO); + segInfo.add(SEGMENTINFO_ESCAPE); + break; + case PathIterator.SEG_CUBICTO: + pntInfo.add(new Point2D.Double(vals[0], vals[1])); + pntInfo.add(new Point2D.Double(vals[2], vals[3])); + pntInfo.add(new Point2D.Double(vals[4], vals[5])); + segInfo.add(SEGMENTINFO_CUBICTO); + segInfo.add(SEGMENTINFO_ESCAPE2); + break; + case PathIterator.SEG_QUADTO: + //TODO: figure out how to convert SEG_QUADTO into SEG_CUBICTO + logger.log(POILogger.WARN, "SEG_QUADTO is not supported"); + break; + case PathIterator.SEG_CLOSE: + pntInfo.add(pntInfo.get(0)); + segInfo.add(SEGMENTINFO_LINETO); + segInfo.add(SEGMENTINFO_ESCAPE); + segInfo.add(SEGMENTINFO_LINETO); + segInfo.add(SEGMENTINFO_CLOSE); + isClosed = true; + break; + } + + it.next(); + } + if(!isClosed) segInfo.add(SEGMENTINFO_LINETO); + segInfo.add(new byte[]{0x00, (byte)0x80}); + + EscherOptRecord opt = getEscherOptRecord(); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4)); + + EscherArrayProperty verticesProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__VERTICES + 0x4000), false, null); + verticesProp.setNumberOfElementsInArray(pntInfo.size()); + verticesProp.setNumberOfElementsInMemory(pntInfo.size()); + verticesProp.setSizeOfElements(0xFFF0); + for (int i = 0; i < pntInfo.size(); i++) { + Point2D.Double pnt = pntInfo.get(i); + byte[] data = new byte[4]; + LittleEndian.putShort(data, 0, (short)((pnt.getX() - bounds.getX())*MASTER_DPI/POINT_DPI)); + LittleEndian.putShort(data, 2, (short)((pnt.getY() - bounds.getY())*MASTER_DPI/POINT_DPI)); + verticesProp.setElement(i, data); + } + opt.addEscherProperty(verticesProp); + + EscherArrayProperty segmentsProp = new EscherArrayProperty((short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000), false, null); + segmentsProp.setNumberOfElementsInArray(segInfo.size()); + segmentsProp.setNumberOfElementsInMemory(segInfo.size()); + segmentsProp.setSizeOfElements(0x2); + for (int i = 0; i < segInfo.size(); i++) { + byte[] seg = segInfo.get(i); + segmentsProp.setElement(i, seg); + } + opt.addEscherProperty(segmentsProp); + + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__RIGHT, (int)(bounds.getWidth()*MASTER_DPI/POINT_DPI))); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__BOTTOM, (int)(bounds.getHeight()*MASTER_DPI/POINT_DPI))); + + opt.sortProperties(); + + setAnchor(bounds); + } + + /** + * Gets the freeform path + * + * @return the freeform path + */ + public GeneralPath getPath(){ + EscherOptRecord opt = getEscherOptRecord(); + opt.addEscherProperty(new EscherSimpleProperty(EscherProperties.GEOMETRY__SHAPEPATH, 0x4)); + + EscherArrayProperty verticesProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__VERTICES + 0x4000)); + if(verticesProp == null) verticesProp = getEscherProperty(opt, EscherProperties.GEOMETRY__VERTICES); + + EscherArrayProperty segmentsProp = getEscherProperty(opt, (short)(EscherProperties.GEOMETRY__SEGMENTINFO + 0x4000)); + if(segmentsProp == null) segmentsProp = getEscherProperty(opt, EscherProperties.GEOMETRY__SEGMENTINFO); + + //sanity check + if(verticesProp == null) { + logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__VERTICES "); + return null; + } + if(segmentsProp == null) { + logger.log(POILogger.WARN, "Freeform is missing GEOMETRY__SEGMENTINFO "); + return null; + } + + GeneralPath path = new GeneralPath(); + int numPoints = verticesProp.getNumberOfElementsInArray(); + int numSegments = segmentsProp.getNumberOfElementsInArray(); + for (int i = 0, j = 0; i < numSegments && j < numPoints; i++) { + byte[] elem = segmentsProp.getElement(i); + if(Arrays.equals(elem, SEGMENTINFO_MOVETO)){ + byte[] p = verticesProp.getElement(j++); + short x = LittleEndian.getShort(p, 0); + short y = LittleEndian.getShort(p, 2); + path.moveTo( + ((float)x*POINT_DPI/MASTER_DPI), + ((float)y*POINT_DPI/MASTER_DPI)); + } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){ + i++; + byte[] p1 = verticesProp.getElement(j++); + short x1 = LittleEndian.getShort(p1, 0); + short y1 = LittleEndian.getShort(p1, 2); + byte[] p2 = verticesProp.getElement(j++); + short x2 = LittleEndian.getShort(p2, 0); + short y2 = LittleEndian.getShort(p2, 2); + byte[] p3 = verticesProp.getElement(j++); + short x3 = LittleEndian.getShort(p3, 0); + short y3 = LittleEndian.getShort(p3, 2); + path.curveTo( + ((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI), + ((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI), + ((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI)); + + } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){ + i++; + byte[] pnext = segmentsProp.getElement(i); + if(Arrays.equals(pnext, SEGMENTINFO_ESCAPE)){ + if(j + 1 < numPoints){ + byte[] p = verticesProp.getElement(j++); + short x = LittleEndian.getShort(p, 0); + short y = LittleEndian.getShort(p, 2); + path.lineTo( + ((float)x*POINT_DPI/MASTER_DPI), ((float)y*POINT_DPI/MASTER_DPI)); + } + } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){ + path.closePath(); + } + } + } + return path; + } + + public java.awt.Shape getOutline(){ + GeneralPath path = getPath(); + if(path == null) { + // return empty path if either GEOMETRY__VERTICES or GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188 + return new GeneralPath(); + } + + Rectangle2D anchor = getAnchor2D(); + Rectangle2D bounds = path.getBounds2D(); + AffineTransform at = new AffineTransform(); + at.translate(anchor.getX(), anchor.getY()); + at.scale( + anchor.getWidth()/bounds.getWidth(), + anchor.getHeight()/bounds.getHeight() + ); + return at.createTransformedShape(path); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java new file mode 100644 index 0000000000..5e47776d6e --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFGroupShape.java @@ -0,0 +1,289 @@ +/* ==================================================================== + 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 java.awt.geom.Rectangle2D; +import java.util.*; + +import org.apache.poi.ddf.*; +import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogger; + +/** + * Represents a group of shapes. + * + * @author Yegor Kozlov + */ +public class HSLFGroupShape extends HSLFShape implements ShapeContainer { + + /** + * Create a new ShapeGroup. This constructor is used when a new shape is created. + * + */ + public HSLFGroupShape(){ + this(null, null); + _escherContainer = createSpContainer(false); + } + + /** + * Create a ShapeGroup object and initilize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected HSLFGroupShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + } + + @Override + public List getShapes() { + return getShapeList(); + } + + /** + * 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){ + + 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)(anchor.y*MASTER_DPI/POINT_DPI)); + clientAnchor.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI)); + clientAnchor.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI)); + clientAnchor.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI)); + + EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); + + spgr.setRectX1(anchor.x*MASTER_DPI/POINT_DPI); + spgr.setRectY1(anchor.y*MASTER_DPI/POINT_DPI); + spgr.setRectX2((anchor.x + anchor.width)*MASTER_DPI/POINT_DPI); + spgr.setRectY2((anchor.y + anchor.height)*MASTER_DPI/POINT_DPI); + } + + /** + * Sets the coordinate space of this group. All children are constrained + * to these coordinates. + * + * @param anchor the coordinate space of this group + */ + public void setCoordinates(Rectangle2D anchor){ + EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); + + int x1 = (int)Math.round(anchor.getX()*MASTER_DPI/POINT_DPI); + int y1 = (int)Math.round(anchor.getY()*MASTER_DPI/POINT_DPI); + int x2 = (int)Math.round((anchor.getX() + anchor.getWidth())*MASTER_DPI/POINT_DPI); + int y2 = (int)Math.round((anchor.getY() + anchor.getHeight())*MASTER_DPI/POINT_DPI); + + spgr.setRectX1(x1); + spgr.setRectY1(y1); + spgr.setRectX2(x2); + spgr.setRectY2(y2); + + } + + /** + * Gets the coordinate space of this group. All children are constrained + * to these coordinates. + * + * @return the coordinate space of this group + */ + public Rectangle2D getCoordinates(){ + EscherSpgrRecord spgr = getEscherChild(EscherSpgrRecord.RECORD_ID); + + Rectangle2D.Float anchor = new Rectangle2D.Float(); + anchor.x = (float)spgr.getRectX1()*POINT_DPI/MASTER_DPI; + anchor.y = (float)spgr.getRectY1()*POINT_DPI/MASTER_DPI; + anchor.width = (float)(spgr.getRectX2() - spgr.getRectX1())*POINT_DPI/MASTER_DPI; + anchor.height = (float)(spgr.getRectY2() - spgr.getRectY1())*POINT_DPI/MASTER_DPI; + + return anchor; + } + + /** + * Create a new ShapeGroup and create an instance of EscherSpgrContainer which represents a group of shapes + */ + protected EscherContainerRecord createSpContainer(boolean isChild) { + EscherContainerRecord spgr = new EscherContainerRecord(); + spgr.setRecordId(EscherContainerRecord.SPGR_CONTAINER); + spgr.setOptions((short)15); + + //The group itself is a shape, and always appears as the first EscherSpContainer in the group container. + EscherContainerRecord spcont = new EscherContainerRecord(); + spcont.setRecordId(EscherContainerRecord.SP_CONTAINER); + spcont.setOptions((short)15); + + EscherSpgrRecord spg = new EscherSpgrRecord(); + spg.setOptions((short)1); + spcont.addChildRecord(spg); + + EscherSpRecord sp = new EscherSpRecord(); + short type = (short)((ShapeType.NOT_PRIMITIVE.nativeId << 4) + 2); + sp.setOptions(type); + sp.setFlags(EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_GROUP); + spcont.addChildRecord(sp); + + EscherClientAnchorRecord anchor = new EscherClientAnchorRecord(); + spcont.addChildRecord(anchor); + + spgr.addChildRecord(spcont); + return spgr; + } + + /** + * Add a shape to this group. + * + * @param shape - the Shape to add + */ + public void addShape(HSLFShape shape){ + _escherContainer.addChildRecord(shape.getSpContainer()); + + HSLFSheet sheet = getSheet(); + shape.setSheet(sheet); + shape.setShapeId(sheet.allocateShapeId()); + shape.afterInsert(sheet); + } + + /** + * Moves this ShapeGroup to the specified location. + *

    + * @param x the x coordinate of the top left corner of the shape in new location + * @param y the y coordinate of the top left corner of the shape in new location + */ + public void moveTo(int x, int y){ + java.awt.Rectangle anchor = getAnchor(); + int dx = x - anchor.x; + int dy = y - anchor.y; + anchor.translate(dx, dy); + setAnchor(anchor); + + + for (HSLFShape shape : getShapes()) { + java.awt.Rectangle chanchor = shape.getAnchor(); + chanchor.translate(dx, dy); + shape.setAnchor(chanchor); + } + } + + /** + * Returns the anchor (the bounding box rectangle) of this shape group. + * All coordinates are expressed in points (72 dpi). + * + * @return the anchor of this shape group + */ + public Rectangle2D getAnchor2D(){ + EscherClientAnchorRecord clientAnchor = getEscherChild(EscherClientAnchorRecord.RECORD_ID); + Rectangle2D.Float anchor = new Rectangle2D.Float(); + if(clientAnchor == null){ + logger.log(POILogger.INFO, "EscherClientAnchorRecord was not found for shape group. Searching for EscherChildAnchorRecord."); + EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID); + anchor = new Rectangle2D.Float( + (float)rec.getDx1()*POINT_DPI/MASTER_DPI, + (float)rec.getDy1()*POINT_DPI/MASTER_DPI, + (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI, + (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI + ); + } else { + anchor.x = (float)clientAnchor.getCol1()*POINT_DPI/MASTER_DPI; + anchor.y = (float)clientAnchor.getFlag()*POINT_DPI/MASTER_DPI; + anchor.width = (float)(clientAnchor.getDx1() - clientAnchor.getCol1())*POINT_DPI/MASTER_DPI ; + anchor.height = (float)(clientAnchor.getRow1() - clientAnchor.getFlag())*POINT_DPI/MASTER_DPI; + } + + return anchor; + } + + /** + * Return type of the shape. + * In most cases shape group type is {@link org.apache.poi.hslf.model.ShapeTypes#NotPrimitive} + * + * @return type of the shape. + */ + public ShapeType getShapeType(){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + int nativeId = spRecord.getOptions() >> 4; + return ShapeType.forId(nativeId, false); + } + + /** + * Returns null - shape groups can't have hyperlinks + * + * @return null. + */ + public HSLFHyperlink getHyperlink(){ + return null; + } + + @Override + public T getEscherChild(int recordId){ + EscherContainerRecord groupInfoContainer = (EscherContainerRecord)_escherContainer.getChild(0); + return groupInfoContainer.getChildById((short)recordId); + } + + public Iterator iterator() { + return getShapeList().iterator(); + } + + public boolean removeShape(HSLFShape shape) { + // TODO: implement! + throw new UnsupportedOperationException(); + } + + /** + * @return the shapes contained in this group container + */ + protected List getShapeList() { + // Out escher container record should contain several + // SpContainers, the first of which is the group shape itself + Iterator iter = _escherContainer.getChildIterator(); + + // Don't include the first SpContainer, it is always NotPrimitive + if (iter.hasNext()) { + iter.next(); + } + List shapeList = new ArrayList(); + while (iter.hasNext()) { + EscherRecord r = iter.next(); + if(r instanceof EscherContainerRecord) { + // Create the Shape for it + EscherContainerRecord container = (EscherContainerRecord)r; + HSLFShape shape = HSLFShapeFactory.createShape(container, this); + shape.setSheet(getSheet()); + shapeList.add( shape ); + } else { + // Should we do anything special with these non + // Container records? + logger.log(POILogger.ERROR, "Shape contained non container escher record, was " + r.getClass().getName()); + } + } + + return shapeList; + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java new file mode 100644 index 0000000000..baead9e31c --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java @@ -0,0 +1,248 @@ +/* ==================================================================== + 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 java.util.*; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.record.*; + +/** + * Represents a hyperlink in a PowerPoint document + * + * @author Yegor Kozlov + */ +public final class HSLFHyperlink { + public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide; + public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide; + public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide; + public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide; + public static final byte LINK_SLIDENUMBER = InteractiveInfoAtom.LINK_SlideNumber; + public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url; + public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL; + + private int id=-1; + private int type; + private String address; + private String title; + private int startIndex, endIndex; + + /** + * Gets the type of the hyperlink action. + * Must be a LINK_* constant + * + * @return the hyperlink URL + * @see InteractiveInfoAtom + */ + public int getType() { + return type; + } + + public void setType(int val) { + type = val; + switch(type){ + case LINK_NEXTSLIDE: + title = "NEXT"; + address = "1,-1,NEXT"; + break; + case LINK_PREVIOUSSLIDE: + title = "PREV"; + address = "1,-1,PREV"; + break; + case LINK_FIRSTSLIDE: + title = "FIRST"; + address = "1,-1,FIRST"; + break; + case LINK_LASTSLIDE: + title = "LAST"; + address = "1,-1,LAST"; + break; + case LINK_SLIDENUMBER: + break; + default: + title = ""; + address = ""; + break; + } + } + + /** + * Gets the hyperlink URL + * + * @return the hyperlink URL + */ + public String getAddress() { + return address; + } + + public void setAddress(HSLFSlide slide) { + String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber(); + setAddress(href);; + setTitle("Slide " + slide.getSlideNumber()); + setType(HSLFHyperlink.LINK_SLIDENUMBER); + } + + public void setAddress(String str) { + address = str; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + /** + * Gets the hyperlink user-friendly title (if different from URL) + * + * @return the hyperlink user-friendly title + */ + public String getTitle() { + return title; + } + + public void setTitle(String str) { + title = str; + } + + /** + * Gets the beginning character position + * + * @return the beginning character position + */ + public int getStartIndex() { + return startIndex; + } + + /** + * Gets the ending character position + * + * @return the ending character position + */ + public int getEndIndex() { + return endIndex; + } + + /** + * Find hyperlinks in a text shape + * + * @param shape TextRun to lookup hyperlinks in + * @return found hyperlinks or null if not found + */ + public static HSLFHyperlink[] find(HSLFTextShape shape){ + List lst = new ArrayList(); + HSLFSlideShow ppt = shape.getSheet().getSlideShow(); + //document-level container which stores info about all links in a presentation + ExObjList exobj = ppt.getDocumentRecord().getExObjList(); + if (exobj == null) { + return null; + } + + Record[] records = shape.getClientRecords(); + find(records, exobj, lst); + + HSLFHyperlink[] links = null; + if (lst.size() > 0){ + links = new HSLFHyperlink[lst.size()]; + lst.toArray(links); + } + return links; + } + + /** + * Find hyperlinks in a text paragraph + * + * @param paragraph TextParagraph to lookup hyperlinks in + * @return found hyperlinks or null if not found + */ + public static HSLFHyperlink[] find(HSLFTextParagraph paragraph){ + List lst = new ArrayList(); + HSLFSlideShow ppt = paragraph.getSheet().getSlideShow(); + //document-level container which stores info about all links in a presentation + ExObjList exobj = ppt.getDocumentRecord().getExObjList(); + if (exobj == null) { + return null; + } + + Record[] records = paragraph.getRecords(); + find(records, exobj, lst); + + HSLFHyperlink[] links = null; + if (lst.size() > 0){ + links = new HSLFHyperlink[lst.size()]; + lst.toArray(links); + } + return links; + } + + /** + * Find hyperlink assigned to the supplied shape + * + * @param shape Shape to lookup hyperlink in + * @return found hyperlink or null + */ + public static HSLFHyperlink find(HSLFShape shape){ + List lst = new ArrayList(); + HSLFSlideShow ppt = shape.getSheet().getSlideShow(); + //document-level container which stores info about all links in a presentation + ExObjList exobj = ppt.getDocumentRecord().getExObjList(); + if (exobj == null) { + return null; + } + + EscherContainerRecord spContainer = shape.getSpContainer(); + for (Iterator it = spContainer.getChildIterator(); it.hasNext(); ) { + EscherRecord obj = it.next(); + if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID){ + byte[] data = obj.serialize(); + Record[] records = Record.findChildRecords(data, 8, data.length-8); + find(records, exobj, lst); + } + } + + return lst.size() == 1 ? (HSLFHyperlink)lst.get(0) : null; + } + + private static void find(Record[] records, ExObjList exobj, List out){ + if (records == null) return; + for (int i = 0; i < records.length; i++) { + //see if we have InteractiveInfo in the textrun's records + if( records[i] instanceof InteractiveInfo){ + InteractiveInfo hldr = (InteractiveInfo)records[i]; + InteractiveInfoAtom info = hldr.getInteractiveInfoAtom(); + int id = info.getHyperlinkID(); + ExHyperlink linkRecord = exobj.get(id); + if (linkRecord != null){ + HSLFHyperlink link = new HSLFHyperlink(); + link.title = linkRecord.getLinkTitle(); + link.address = linkRecord.getLinkURL(); + link.type = info.getAction(); + + if (++i < records.length && records[i] instanceof TxInteractiveInfoAtom){ + TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)records[i]; + link.startIndex = txinfo.getStartIndex(); + link.endIndex = txinfo.getEndIndex(); + } + out.add(link); + } + } + } + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFMasterSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFMasterSheet.java new file mode 100644 index 0000000000..974a858616 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFMasterSheet.java @@ -0,0 +1,56 @@ +/* ==================================================================== + 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.hslf.record.SheetContainer; +import org.apache.poi.hslf.model.textproperties.TextProp; +import org.apache.poi.sl.usermodel.MasterSheet; + +/** + * The superclass of all master sheets - Slide masters, Notes masters, etc. + * + * For now it's empty. When we understand more about masters in ppt we will add the common functionality here. + * + * @author Yegor Kozlov + */ +public abstract class HSLFMasterSheet extends HSLFSheet implements MasterSheet { + public HSLFMasterSheet(SheetContainer container, int sheetNo){ + super(container, sheetNo); + } + + /** + * Pickup a style attribute from the master. + * This is the "workhorse" which returns the default style attrubutes. + */ + public abstract TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) ; + + + /** + * Checks if the shape is a placeholder. + * (placeholders aren't normal shapes, they are visible only in the Edit Master mode) + * + * + * @return true if the shape is a placeholder + */ + public static boolean isPlaceholder(HSLFShape shape){ + if(!(shape instanceof HSLFTextShape)) return false; + + HSLFTextShape tx = (HSLFTextShape)shape; + return tx.getPlaceholderAtom() != null; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java new file mode 100644 index 0000000000..50eb3a6db2 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java @@ -0,0 +1,79 @@ +/* ==================================================================== + 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 java.util.ArrayList; +import java.util.List; + +import org.apache.poi.sl.usermodel.Notes; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * This class represents a slide's notes in a PowerPoint Document. It + * allows access to the text within, and the layout. For now, it only + * does the text side of things though + * + * @author Nick Burch + */ + +public final class HSLFNotes extends HSLFSheet implements Notes { + protected static POILogger logger = POILogFactory.getLogger(HSLFNotes.class); + + private List> _runs; + + /** + * Constructs a Notes Sheet from the given Notes record. + * Initialises TextRuns, to provide easier access to the text + * + * @param notes the Notes record to read from + */ + public HSLFNotes(org.apache.poi.hslf.record.Notes notes) { + super(notes, notes.getNotesAtom().getSlideID()); + + // Now, build up TextRuns from pairs of TextHeaderAtom and + // one of TextBytesAtom or TextCharsAtom, found inside + // EscherTextboxWrapper's in the PPDrawing + _runs = HSLFTextParagraph.findTextParagraphs(getPPDrawing()); + if (_runs.isEmpty()) { + logger.log(POILogger.WARN, "No text records found for notes sheet"); + } + + // Set the sheet on each TextRun + for (List ltp : _runs) { + for (HSLFTextParagraph tp : ltp) { + tp.supplySheet(this); + } + } + } + + /** + * Returns an array of all the TextParagraphs found + */ + @Override + public List> getTextParagraphs() { + return _runs; + } + + /** + * Return null - Notes Masters are not yet supported + */ + public HSLFMasterSheet getMasterSheet() { + return null; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureData.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureData.java index 9d9b0dc594..b848a2cb9b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureData.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureData.java @@ -30,7 +30,6 @@ import org.apache.poi.hslf.blip.JPEG; import org.apache.poi.hslf.blip.PICT; import org.apache.poi.hslf.blip.PNG; import org.apache.poi.hslf.blip.WMF; -import org.apache.poi.hslf.model.HSLFPictureShape; import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.HashAlgorithm; import org.apache.poi.util.LittleEndian; diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java new file mode 100644 index 0000000000..c97c281680 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFPictureShape.java @@ -0,0 +1,279 @@ +/* ==================================================================== + 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 java.awt.Insets; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.List; + +import javax.imageio.ImageIO; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.blip.Bitmap; +import org.apache.poi.hslf.record.Document; +import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.util.*; + + +/** + * Represents a picture in a PowerPoint document. + * + * @author Yegor Kozlov + */ +public class HSLFPictureShape extends HSLFSimpleShape { + + /** + * Windows Enhanced Metafile (EMF) + */ + public static final int EMF = 2; + + /** + * Windows Metafile (WMF) + */ + public static final int WMF = 3; + + /** + * Macintosh PICT + */ + public static final int PICT = 4; + + /** + * JPEG + */ + public static final int JPEG = 5; + + /** + * PNG + */ + public static final int PNG = 6; + + /** + * Windows DIB (BMP) + */ + public static final byte DIB = 7; + + /** + * Create a new Picture + * + * @param idx the index of the picture + */ + public HSLFPictureShape(int idx){ + this(idx, null); + } + + /** + * Create a new Picture + * + * @param idx the index of the picture + * @param parent the parent shape + */ + public HSLFPictureShape(int idx, ShapeContainer parent) { + super(null, parent); + _escherContainer = createSpContainer(idx, parent instanceof HSLFGroupShape); + } + + /** + * Create a Picture object + * + * @param escherRecord the EscherSpContainer record which holds information about + * this picture in the Slide + * @param parent the parent shape of this picture + */ + protected HSLFPictureShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + } + + /** + * Returns index associated with this picture. + * Index starts with 1 and points to a EscherBSE record which + * holds information about this picture. + * + * @return the index to this picture (1 based). + */ + public int getPictureIndex(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPTODISPLAY); + return prop == null ? 0 : prop.getPropertyValue(); + } + + /** + * Create a new Picture and populate the inital structure of the EscherSp record which holds information about this picture. + + * @param idx the index of the picture which refers to EscherBSE container. + * @return the create Picture object + */ + protected EscherContainerRecord createSpContainer(int idx, boolean isChild) { + _escherContainer = super.createSpContainer(isChild); + _escherContainer.setOptions((short)15); + + EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID); + spRecord.setOptions((short)((ShapeType.FRAME.nativeId << 4) | 0x2)); + + //set default properties for a picture + EscherOptRecord opt = getEscherOptRecord(); + setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x800080); + + //another weird feature of powerpoint: for picture id we must add 0x4000. + setEscherProperty(opt, (short)(EscherProperties.BLIP__BLIPTODISPLAY + 0x4000), idx); + + return _escherContainer; + } + + /** + * Resize this picture to the default size. + * For PNG and JPEG resizes the image to 100%, + * for other types sets the default size of 200x200 pixels. + */ + public void setDefaultSize(){ + HSLFPictureData pict = getPictureData(); + if (pict instanceof Bitmap){ + BufferedImage img = null; + try { + img = ImageIO.read(new ByteArrayInputStream(pict.getData())); + } + catch (IOException e){} + catch (NegativeArraySizeException ne) {} + + if(img != null) { + // Valid image, set anchor from it + setAnchor(new java.awt.Rectangle(0, 0, img.getWidth()*POINT_DPI/PIXEL_DPI, img.getHeight()*POINT_DPI/PIXEL_DPI)); + } else { + // Invalid image, go with the default metafile size + setAnchor(new java.awt.Rectangle(0, 0, 200, 200)); + } + } else { + //default size of a metafile picture is 200x200 + setAnchor(new java.awt.Rectangle(50, 50, 200, 200)); + } + } + + /** + * Returns the picture data for this picture. + * + * @return the picture data for this picture. + */ + public HSLFPictureData getPictureData(){ + HSLFSlideShow ppt = getSheet().getSlideShow(); + HSLFPictureData[] pict = ppt.getPictureData(); + + EscherBSERecord bse = getEscherBSERecord(); + if (bse == null){ + logger.log(POILogger.ERROR, "no reference to picture data found "); + } else { + for ( int i = 0; i < pict.length; i++ ) { + if (pict[i].getOffset() == bse.getOffset()){ + return pict[i]; + } + } + logger.log(POILogger.ERROR, "no picture found for our BSE offset " + bse.getOffset()); + } + return null; + } + + protected EscherBSERecord getEscherBSERecord(){ + HSLFSlideShow ppt = getSheet().getSlideShow(); + Document doc = ppt.getDocumentRecord(); + EscherContainerRecord dggContainer = doc.getPPDrawingGroup().getDggContainer(); + EscherContainerRecord bstore = HSLFShape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER); + if(bstore == null) { + logger.log(POILogger.DEBUG, "EscherContainerRecord.BSTORE_CONTAINER was not found "); + return null; + } + List lst = bstore.getChildRecords(); + int idx = getPictureIndex(); + if (idx == 0){ + logger.log(POILogger.DEBUG, "picture index was not found, returning "); + return null; + } + return (EscherBSERecord)lst.get(idx-1); + } + + /** + * Name of this picture. + * + * @return name of this picture + */ + public String getPictureName(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherComplexProperty prop = getEscherProperty(opt, EscherProperties.BLIP__BLIPFILENAME); + if (prop == null) return null; + String name = StringUtil.getFromUnicodeLE(prop.getComplexData()); + return name.trim(); + } + + /** + * Name of this picture. + * + * @param name of this picture + */ + public void setPictureName(String name){ + EscherOptRecord opt = getEscherOptRecord(); + byte[] data = StringUtil.getToUnicodeLE(name + '\u0000'); + EscherComplexProperty prop = new EscherComplexProperty(EscherProperties.BLIP__BLIPFILENAME, false, data); + opt.addEscherProperty(prop); + } + + /** + * By default set the orininal image size + */ + protected void afterInsert(HSLFSheet sh){ + super.afterInsert(sh); + + EscherBSERecord bse = getEscherBSERecord(); + bse.setRef(bse.getRef() + 1); + + java.awt.Rectangle anchor = getAnchor(); + if (anchor.equals(new java.awt.Rectangle())){ + setDefaultSize(); + } + } + + /** + * Returns the clipping values as percent ratio relatively to the image size. + * The anchor specified by {@link #getLogicalAnchor2D()} is the displayed size, + * i.e. the size of the already clipped image + * + * @return the clipping as insets converted/scaled to 100000 (=100%) + */ + public Insets getBlipClip() { + EscherOptRecord opt = getEscherOptRecord(); + + double top = getFractProp(opt, EscherProperties.BLIP__CROPFROMTOP); + double bottom = getFractProp(opt, EscherProperties.BLIP__CROPFROMBOTTOM); + double left = getFractProp(opt, EscherProperties.BLIP__CROPFROMLEFT); + double right = getFractProp(opt, EscherProperties.BLIP__CROPFROMRIGHT); + + // if all crop values are zero (the default) then no crop rectangle is set, return null + return (top==0 && bottom==0 && left==0 && right==0) + ? null + : new Insets((int)(top*100000), (int)(left*100000), (int)(bottom*100000), (int)(right*100000)); + } + + /** + * @return the fractional property or 0 if not defined + */ + private static double getFractProp(EscherOptRecord opt, short propertyId) { + EscherSimpleProperty prop = getEscherProperty(opt, propertyId); + if (prop == null) return 0; + int fixedPoint = prop.getPropertyValue(); + return Units.fixedPointToDouble(fixedPoint); + } +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java new file mode 100644 index 0000000000..adb61e6d9e --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShape.java @@ -0,0 +1,526 @@ +/* ==================================================================== + 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 java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; +import java.util.Iterator; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.record.ColorSchemeAtom; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.util.*; + +/** + *

    + * Represents a Shape which is the elemental object that composes a drawing. + * This class is a wrapper around EscherSpContainer which holds all information + * about a shape in PowerPoint document. + *

    + *

    + * When you add a shape, you usually specify the dimensions of the shape and the position + * of the upper'left corner of the bounding box for the shape relative to the upper'left + * corner of the page, worksheet, or slide. Distances in the drawing layer are measured + * in points (72 points = 1 inch). + *

    + *

    + * + * @author Yegor Kozlov + */ +public abstract class HSLFShape implements Shape { + + // For logging + protected POILogger logger = POILogFactory.getLogger(this.getClass()); + + /** + * In Escher absolute distances are specified in + * English Metric Units (EMUs), occasionally referred to as A units; + * there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point. + */ + public static final int EMU_PER_INCH = 914400; + public static final int EMU_PER_POINT = 12700; + public static final int EMU_PER_CENTIMETER = 360000; + + /** + * Master DPI (576 pixels per inch). + * Used by the reference coordinate system in PowerPoint. + */ + public static final int MASTER_DPI = 576; + + /** + * Pixels DPI (96 pixels per inch) + */ + public static final int PIXEL_DPI = 96; + + /** + * Points DPI (72 pixels per inch) + */ + public static final int POINT_DPI = 72; + + /** + * Either EscherSpContainer or EscheSpgrContainer record + * which holds information about this shape. + */ + protected EscherContainerRecord _escherContainer; + + /** + * Parent of this shape. + * null for the topmost shapes. + */ + protected ShapeContainer _parent; + + /** + * The Sheet this shape belongs to + */ + protected HSLFSheet _sheet; + + /** + * Fill + */ + protected HSLFFill _fill; + + /** + * Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of this Shape + */ + protected HSLFShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + _escherContainer = escherRecord; + _parent = parent; + } + + /** + * Creates the lowerlevel escher records for this shape. + */ + protected abstract EscherContainerRecord createSpContainer(boolean isChild); + + /** + * @return the parent of this shape + */ + public ShapeContainer getParent(){ + return _parent; + } + + /** + * @return name of the shape. + */ + public String getShapeName(){ + 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 ); + spRecord.setVersion( (short) 0x2 ); + } + + /** + * Returns the anchor (the bounding box rectangle) of this shape. + * All coordinates are expressed in points (72 dpi). + * + * @return the anchor of this shape + */ + public java.awt.Rectangle getAnchor(){ + Rectangle2D anchor2d = getAnchor2D(); + return anchor2d.getBounds(); + } + + /** + * Returns the anchor (the bounding box rectangle) of this shape. + * All coordinates are expressed in points (72 dpi). + * + * @return the anchor of this shape + */ + public Rectangle2D getAnchor2D(){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + int flags = spRecord.getFlags(); + Rectangle2D anchor=null; + if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ + EscherChildAnchorRecord rec = getEscherChild(EscherChildAnchorRecord.RECORD_ID); + anchor = new java.awt.Rectangle(); + if(rec == null){ + logger.log(POILogger.WARN, "EscherSpRecord.FLAG_CHILD is set but EscherChildAnchorRecord was not found"); + EscherClientAnchorRecord clrec = getEscherChild(EscherClientAnchorRecord.RECORD_ID); + anchor = new java.awt.Rectangle(); + anchor = new Rectangle2D.Float( + (float)clrec.getCol1()*POINT_DPI/MASTER_DPI, + (float)clrec.getFlag()*POINT_DPI/MASTER_DPI, + (float)(clrec.getDx1()-clrec.getCol1())*POINT_DPI/MASTER_DPI, + (float)(clrec.getRow1()-clrec.getFlag())*POINT_DPI/MASTER_DPI + ); + } else { + anchor = new Rectangle2D.Float( + (float)rec.getDx1()*POINT_DPI/MASTER_DPI, + (float)rec.getDy1()*POINT_DPI/MASTER_DPI, + (float)(rec.getDx2()-rec.getDx1())*POINT_DPI/MASTER_DPI, + (float)(rec.getDy2()-rec.getDy1())*POINT_DPI/MASTER_DPI + ); + } + } + else { + EscherClientAnchorRecord rec = getEscherChild(EscherClientAnchorRecord.RECORD_ID); + anchor = new java.awt.Rectangle(); + anchor = new Rectangle2D.Float( + (float)rec.getCol1()*POINT_DPI/MASTER_DPI, + (float)rec.getFlag()*POINT_DPI/MASTER_DPI, + (float)(rec.getDx1()-rec.getCol1())*POINT_DPI/MASTER_DPI, + (float)(rec.getRow1()-rec.getFlag())*POINT_DPI/MASTER_DPI + ); + } + return anchor; + } + + public Rectangle2D getLogicalAnchor2D(){ + return getAnchor2D(); + } + + /** + * Sets the anchor (the bounding box rectangle) of this shape. + * All coordinates should be expressed in points (72 dpi). + * + * @param anchor new anchor + */ + public void setAnchor(Rectangle2D anchor){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + int flags = spRecord.getFlags(); + if ((flags & EscherSpRecord.FLAG_CHILD) != 0){ + EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(EscherChildAnchorRecord.RECORD_ID); + rec.setDx1((int)(anchor.getX()*MASTER_DPI/POINT_DPI)); + rec.setDy1((int)(anchor.getY()*MASTER_DPI/POINT_DPI)); + rec.setDx2((int)((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI)); + rec.setDy2((int)((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI)); + } + else { + EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(EscherClientAnchorRecord.RECORD_ID); + rec.setFlag((short)(anchor.getY()*MASTER_DPI/POINT_DPI)); + rec.setCol1((short)(anchor.getX()*MASTER_DPI/POINT_DPI)); + rec.setDx1((short)(((anchor.getWidth() + anchor.getX())*MASTER_DPI/POINT_DPI))); + rec.setRow1((short)(((anchor.getHeight() + anchor.getY())*MASTER_DPI/POINT_DPI))); + } + + } + + /** + * Moves the top left corner of the shape to the specified point. + * + * @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){ + Rectangle2D anchor = getAnchor2D(); + anchor.setRect(x, y, anchor.getWidth(), anchor.getHeight()); + setAnchor(anchor); + } + + /** + * Helper method to return escher child by record ID + * + * @return escher record or null if not found. + */ + public static T getEscherChild(EscherContainerRecord owner, int recordId){ + return owner.getChildById((short)recordId); + } + + public T getEscherChild(int recordId){ + return _escherContainer.getChildById((short)recordId); + } + + /** + * Returns escher property by id. + * + * @return escher property or null if not found. + */ + public static T getEscherProperty(EscherOptRecord opt, int propId){ + return opt.lookup(propId); + } + + /** + * Set an escher property for this shape. + * + * @param opt The opt record to set the properties to. + * @param propId The id of the property. One of the constants defined in EscherOptRecord. + * @param value value of the property. If value = -1 then the property is removed. + */ + public static void setEscherProperty(EscherOptRecord opt, short propId, int value){ + java.util.List props = opt.getEscherProperties(); + for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) { + if (iterator.next().getPropertyNumber() == propId){ + iterator.remove(); + break; + } + } + if (value != -1) { + opt.addEscherProperty(new EscherSimpleProperty(propId, value)); + opt.sortProperties(); + } + } + + /** + * Set an simple escher property for this shape. + * + * @param propId The id of the property. One of the constants defined in EscherOptRecord. + * @param value value of the property. If value = -1 then the property is removed. + */ + public void setEscherProperty(short propId, int value){ + EscherOptRecord opt = getEscherOptRecord(); + setEscherProperty(opt, propId, value); + } + + /** + * Get the value of a simple escher property for this shape. + * + * @param propId The id of the property. One of the constants defined in EscherOptRecord. + */ + public int getEscherProperty(short propId){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, propId); + return prop == null ? 0 : prop.getPropertyValue(); + } + + /** + * Get the value of a simple escher property for this shape. + * + * @param propId The id of the property. One of the constants defined in EscherOptRecord. + */ + public int getEscherProperty(short propId, int defaultValue){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, propId); + return prop == null ? defaultValue : prop.getPropertyValue(); + } + + /** + * @return The shape container and it's children that can represent this + * shape. + */ + public EscherContainerRecord getSpContainer(){ + return _escherContainer; + } + + /** + * Event which fires when a shape is inserted in the sheet. + * In some cases we need to propagate changes to upper level containers. + *
    + * Default implementation does nothing. + * + * @param sh - owning shape + */ + protected void afterInsert(HSLFSheet sh){ + if(_fill != null) { + _fill.afterInsert(sh); + } + } + + /** + * @return the SlideShow this shape belongs to + */ + public HSLFSheet getSheet(){ + return _sheet; + } + + /** + * Assign the SlideShow this shape belongs to + * + * @param sheet owner of this shape + */ + public void setSheet(HSLFSheet sheet){ + _sheet = sheet; + } + + Color getColor(short colorProperty, short opacityProperty, int defaultColor){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty p = getEscherProperty(opt, colorProperty); + if(p == null && defaultColor == -1) return null; + + int val = (p == null) ? defaultColor : p.getPropertyValue(); + + EscherColorRef ecr = new EscherColorRef(val); + + boolean fPaletteIndex = ecr.hasPaletteIndexFlag(); + boolean fPaletteRGB = ecr.hasPaletteRGBFlag(); + boolean fSystemRGB = ecr.hasSystemRGBFlag(); + boolean fSchemeIndex = ecr.hasSchemeIndexFlag(); + boolean fSysIndex = ecr.hasSysIndexFlag(); + + int rgb[] = ecr.getRGB(); + + HSLFSheet sheet = getSheet(); + if (fSchemeIndex && sheet != null) { + //red is the index to the color scheme + ColorSchemeAtom ca = sheet.getColorScheme(); + int schemeColor = ca.getColor(ecr.getSchemeIndex()); + + rgb[0] = (schemeColor >> 0) & 0xFF; + rgb[1] = (schemeColor >> 8) & 0xFF; + rgb[2] = (schemeColor >> 16) & 0xFF; + } else if (fPaletteIndex){ + //TODO + } else if (fPaletteRGB){ + //TODO + } else if (fSystemRGB){ + //TODO + } else if (fSysIndex){ + //TODO + } + + double alpha = getAlpha(opacityProperty); + return new Color(rgb[0], rgb[1], rgb[2], (int)(alpha*255.0)); + } + + double getAlpha(short opacityProperty) { + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty op = getEscherProperty(opt, opacityProperty); + int defaultOpacity = 0x00010000; + int opacity = (op == null) ? defaultOpacity : op.getPropertyValue(); + return Units.fixedPointToDouble(opacity); + } + + Color toRGB(int val){ + int a = (val >> 24) & 0xFF; + int b = (val >> 16) & 0xFF; + int g = (val >> 8) & 0xFF; + int r = (val >> 0) & 0xFF; + + if(a == 0xFE){ + // Color is an sRGB value specified by red, green, and blue fields. + } else if (a == 0xFF){ + // Color is undefined. + } else { + // index in the color scheme + ColorSchemeAtom ca = getSheet().getColorScheme(); + int schemeColor = ca.getColor(a); + + r = (schemeColor >> 0) & 0xFF; + g = (schemeColor >> 8) & 0xFF; + b = (schemeColor >> 16) & 0xFF; + } + return new Color(r, g, b); + } + + /** + * @return id for the shape. + */ + public int getShapeId(){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + return spRecord == null ? 0 : spRecord.getShapeId(); + } + + /** + * Sets shape ID + * + * @param id of the shape + */ + public void setShapeId(int id){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + if(spRecord != null) spRecord.setShapeId(id); + } + + /** + * Fill properties of this shape + * + * @return fill properties of this shape + */ + public HSLFFill getFill(){ + if(_fill == null) { + _fill = new HSLFFill(this); + } + return _fill; + } + + public FillStyle getFillStyle() { + return getFill().getFillStyle(); + } + + /** + * Returns the hyperlink assigned to this shape + * + * @return the hyperlink assigned to this shape + * or null if not found. + */ + public HSLFHyperlink getHyperlink(){ + return HSLFHyperlink.find(this); + } + + public void draw(Graphics2D graphics){ + logger.log(POILogger.INFO, "Rendering " + getShapeName()); + } + + /** + * Return shape outline as a java.awt.Shape object + * + * @return the shape outline + */ + public java.awt.Shape getOutline(){ + return getLogicalAnchor2D(); + } + + public EscherOptRecord getEscherOptRecord() { + return getEscherChild(EscherOptRecord.RECORD_ID); + } + + public boolean getFlipHorizontal(){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPHORIZ) != 0; + } + + public void setFlipHorizontal(boolean flip) { + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + int flag = spRecord.getFlags() | EscherSpRecord.FLAG_FLIPHORIZ; + spRecord.setFlags(flag); + } + + public boolean getFlipVertical(){ + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + return (spRecord.getFlags()& EscherSpRecord.FLAG_FLIPVERT) != 0; + } + + public void setFlipVertical(boolean flip) { + EscherSpRecord spRecord = getEscherChild(EscherSpRecord.RECORD_ID); + int flag = spRecord.getFlags() | EscherSpRecord.FLAG_FLIPVERT; + spRecord.setFlags(flag); + } + + public double getRotation(){ + int rot = getEscherProperty(EscherProperties.TRANSFORM__ROTATION); + double angle = Units.fixedPointToDouble(rot) % 360.0; + return angle; + } + + public void setRotation(double theta){ + int rot = Units.doubleToFixedPoint(theta % 360.0); + setEscherProperty(EscherProperties.TRANSFORM__ROTATION, rot); + } + + public boolean isPlaceholder() { + return false; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java new file mode 100644 index 0000000000..0f9dd2815e --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFShapeFactory.java @@ -0,0 +1,159 @@ +/* ==================================================================== + 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 java.util.Iterator; +import java.util.List; + +import org.apache.poi.ddf.EscherClientDataRecord; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherOptRecord; +import org.apache.poi.ddf.EscherProperties; +import org.apache.poi.ddf.EscherProperty; +import org.apache.poi.ddf.EscherPropertyFactory; +import org.apache.poi.ddf.EscherRecord; +import org.apache.poi.ddf.EscherSimpleProperty; +import org.apache.poi.ddf.EscherSpRecord; +import org.apache.poi.hslf.model.*; +import org.apache.poi.hslf.record.InteractiveInfo; +import org.apache.poi.hslf.record.InteractiveInfoAtom; +import org.apache.poi.hslf.record.OEShapeAtom; +import org.apache.poi.hslf.record.Record; +import org.apache.poi.hslf.record.RecordTypes; +import org.apache.poi.hslf.usermodel.*; +import org.apache.poi.sl.usermodel.ShapeContainer; +import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * Create a Shape object depending on its type + * + * @author Yegor Kozlov + */ +public final class HSLFShapeFactory { + // For logging + protected static final POILogger logger = POILogFactory.getLogger(HSLFShapeFactory.class); + + /** + * Create a new shape from the data provided. + */ + public static HSLFShape createShape(EscherContainerRecord spContainer, ShapeContainer parent){ + if (spContainer.getRecordId() == EscherContainerRecord.SPGR_CONTAINER){ + return createShapeGroup(spContainer, parent); + } + return createSimpleShape(spContainer, parent); + } + + public static HSLFGroupShape createShapeGroup(EscherContainerRecord spContainer, ShapeContainer parent){ + HSLFGroupShape group = null; + EscherRecord opt = HSLFShape.getEscherChild((EscherContainerRecord)spContainer.getChild(0), (short)0xF122); + if(opt != null){ + try { + EscherPropertyFactory f = new EscherPropertyFactory(); + List props = f.createProperties( opt.serialize(), 8, opt.getInstance() ); + EscherSimpleProperty p = (EscherSimpleProperty)props.get(0); + if(p.getPropertyNumber() == 0x39F && p.getPropertyValue() == 1){ + group = new Table(spContainer, parent); + } else { + group = new HSLFGroupShape(spContainer, parent); + } + } catch (Exception e){ + logger.log(POILogger.WARN, e.getMessage()); + group = new HSLFGroupShape(spContainer, parent); + } + } else { + group = new HSLFGroupShape(spContainer, parent); + } + + return group; + } + + public static HSLFShape createSimpleShape(EscherContainerRecord spContainer, ShapeContainer parent){ + HSLFShape shape = null; + EscherSpRecord spRecord = spContainer.getChildById(EscherSpRecord.RECORD_ID); + + ShapeType type = ShapeType.forId(spRecord.getShapeType(), false); + switch (type){ + case TEXT_BOX: + 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); + break; + } + case LINE: + shape = new Line(spContainer, parent); + break; + case NOT_PRIMITIVE: { + EscherOptRecord 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.WARN, "Creating AutoShape for a NotPrimitive shape"); + shape = new HSLFAutoShape(spContainer, parent); + } + break; + } + default: + shape = new HSLFAutoShape(spContainer, parent); + break; + } + return shape; + + } + + @SuppressWarnings("unchecked") + protected static T getClientDataRecord(EscherContainerRecord spContainer, int recordType) { + Record oep = null; + for (Iterator it = spContainer.getChildIterator(); it.hasNext();) { + EscherRecord obj = it.next(); + if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID) { + byte[] data = obj.serialize(); + Record[] records = Record.findChildRecords(data, 8, data.length - 8); + for (int j = 0; j < records.length; j++) { + if (records[j].getRecordType() == recordType) { + return (T)records[j]; + } + } + } + } + return (T)oep; + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java new file mode 100644 index 0000000000..e5b704b777 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java @@ -0,0 +1,403 @@ +/* ==================================================================== + 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 java.awt.Graphics2D; +import java.util.*; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.record.*; +import org.apache.poi.sl.usermodel.Sheet; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * This class defines the common format of "Sheets" in a powerpoint + * document. Such sheets could be Slides, Notes, Master etc + * + * @author Nick Burch + * @author Yegor Kozlov + */ + +public abstract class HSLFSheet implements Sheet { + private static POILogger logger = POILogFactory.getLogger(HSLFSheet.class); + + /** + * The SlideShow we belong to + */ + private HSLFSlideShow _slideShow; + + /** + * Sheet background + */ + private HSLFBackground _background; + + /** + * Record container that holds sheet data. + * For slides it is org.apache.poi.hslf.record.Slide, + * for notes it is org.apache.poi.hslf.record.Notes, + * for slide masters it is org.apache.poi.hslf.record.SlideMaster, etc. + */ + private SheetContainer _container; + + private int _sheetNo; + + public HSLFSheet(SheetContainer container, int sheetNo) { + _container = container; + _sheetNo = sheetNo; + } + + /** + * Returns an array of all the TextRuns in the sheet. + */ + public abstract List> getTextParagraphs(); + + /** + * Returns the (internal, RefID based) sheet number, as used + * to in PersistPtr stuff. + */ + public int _getSheetRefId() { + return _container.getSheetId(); + } + + /** + * Returns the (internal, SlideIdentifier based) sheet number, as used + * to reference this sheet from other records. + */ + public int _getSheetNumber() { + return _sheetNo; + } + + /** + * Fetch the PPDrawing from the underlying record + */ + public PPDrawing getPPDrawing() { + return _container.getPPDrawing(); + } + + /** + * Fetch the SlideShow we're attached to + */ + public HSLFSlideShow getSlideShow() { + return _slideShow; + } + + /** + * Return record container for this sheet + */ + public SheetContainer getSheetContainer() { + return _container; + } + + /** + * Set the SlideShow we're attached to. + * Also passes it on to our child RichTextRuns + */ + public void setSlideShow(HSLFSlideShow ss) { + _slideShow = ss; + List> trs = getTextParagraphs(); + if (trs == null) return; + for (List ltp : trs) { + for (HSLFTextParagraph tp : ltp) { + tp.supplySheet(this); + } + } + } + + + /** + * Returns all shapes contained in this Sheet + * + * @return all shapes contained in this Sheet (Slide or Notes) + */ + @Override + public List getShapes() { + return getShapeList(); + } + + /** + * Add a new Shape to this Slide + * + * @param shape - the Shape to add + */ + public void addShape(HSLFShape shape) { + PPDrawing ppdrawing = getPPDrawing(); + + EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; + EscherContainerRecord spgr = (EscherContainerRecord) HSLFShape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER); + spgr.addChildRecord(shape.getSpContainer()); + + shape.setSheet(this); + shape.setShapeId(allocateShapeId()); + shape.afterInsert(this); + } + + /** + * Allocates new shape id for the new drawing group id. + * + * @return a new shape id. + */ + public int allocateShapeId() + { + EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); + EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord(); + + dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 ); + + // Add to existing cluster if space available + for (int i = 0; i < dgg.getFileIdClusters().length; i++) + { + EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i]; + if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024) + { + int result = c.getNumShapeIdsUsed() + (1024 * (i+1)); + c.incrementShapeId(); + dg.setNumShapes( dg.getNumShapes() + 1 ); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; + } + } + + // Create new cluster + dgg.addCluster( dg.getDrawingGroupId(), 0, false ); + dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId(); + dg.setNumShapes( dg.getNumShapes() + 1 ); + int result = (1024 * dgg.getFileIdClusters().length); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; + } + + /** + * Removes the specified shape from this sheet. + * + * @param shape shape to be removed from this sheet, if present. + * @return true if the shape was deleted. + */ + public boolean removeShape(HSLFShape shape) { + PPDrawing ppdrawing = getPPDrawing(); + + EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; + EscherContainerRecord spgr = null; + + for (Iterator it = dg.getChildIterator(); it.hasNext();) { + EscherRecord rec = it.next(); + if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) { + spgr = (EscherContainerRecord) rec; + break; + } + } + if(spgr == null) { + return false; + } + + List lst = spgr.getChildRecords(); + boolean result = lst.remove(shape.getSpContainer()); + spgr.setChildRecords(lst); + return result; + } + + /** + * Called by SlideShow ater a new sheet is created + */ + public void onCreate(){ + + } + + /** + * Return the master sheet . + */ + public abstract HSLFMasterSheet getMasterSheet(); + + /** + * Color scheme for this sheet. + */ + public ColorSchemeAtom getColorScheme() { + return _container.getColorScheme(); + } + + /** + * Returns the background shape for this sheet. + * + * @return the background shape for this sheet. + */ + public HSLFBackground getBackground() { + if (_background == null) { + PPDrawing ppdrawing = getPPDrawing(); + + EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; + EscherContainerRecord spContainer = null; + + for (Iterator it = dg.getChildIterator(); it.hasNext();) { + EscherRecord rec = it.next(); + if (rec.getRecordId() == EscherContainerRecord.SP_CONTAINER) { + spContainer = (EscherContainerRecord) rec; + break; + } + } + _background = new HSLFBackground(spContainer, null); + _background.setSheet(this); + } + return _background; + } + + public void draw(Graphics2D graphics){ + + } + + /** + * Subclasses should call this method and update the array of text runs + * when a text shape is added + * + * @param shape + */ + protected void onAddTextShape(HSLFTextShape shape) { + + } + + /** + * Return placeholder by text type + * + * @param type type of text, See {@link org.apache.poi.hslf.record.TextHeaderAtom} + * @return TextShape or null + */ + public HSLFTextShape getPlaceholderByTextType(int type){ + for (HSLFShape shape : getShapes()) { + if(shape instanceof HSLFTextShape){ + HSLFTextShape tx = (HSLFTextShape)shape; + if (tx != null && tx.getRunType() == type) { + return tx; + } + } + } + return null; + } + + /** + * Search text placeholer by its type + * + * @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom} + * @return TextShape or null + */ + public HSLFTextShape getPlaceholder(int type){ + for (HSLFShape shape : getShapes()) { + if(shape instanceof HSLFTextShape){ + HSLFTextShape tx = (HSLFTextShape)shape; + int placeholderId = 0; + OEPlaceholderAtom oep = tx.getPlaceholderAtom(); + if(oep != null) { + placeholderId = oep.getPlaceholderId(); + } else { + //special case for files saved in Office 2007 + RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID); + if(hldr != null) placeholderId = hldr.getPlaceholderId(); + } + if(placeholderId == type){ + return tx; + } + } + } + return null; + } + + /** + * Return programmable tag associated with this sheet, e.g. ___PPT12. + * + * @return programmable tag associated with this sheet. + */ + public String getProgrammableTag(){ + String tag = null; + RecordContainer progTags = (RecordContainer) + getSheetContainer().findFirstOfType( + RecordTypes.ProgTags.typeID + ); + if(progTags != null) { + RecordContainer progBinaryTag = (RecordContainer) + progTags.findFirstOfType( + RecordTypes.ProgBinaryTag.typeID + ); + if(progBinaryTag != null) { + CString binaryTag = (CString) + progBinaryTag.findFirstOfType( + RecordTypes.CString.typeID + ); + if(binaryTag != null) tag = binaryTag.getText(); + } + } + + return tag; + + } + + public Iterator iterator() { + return getShapeList().iterator(); + } + + + /** + * Returns all shapes contained in this Sheet + * + * @return all shapes contained in this Sheet (Slide or Notes) + */ + protected List getShapeList() { + PPDrawing ppdrawing = getPPDrawing(); + + EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; + EscherContainerRecord spgr = null; + + for (Iterator it = dg.getChildIterator(); it.hasNext();) { + EscherRecord rec = it.next(); + if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) { + spgr = (EscherContainerRecord) rec; + break; + } + } + if (spgr == null) { + throw new IllegalStateException("spgr not found"); + } + + List shapeList = new ArrayList(); + Iterator it = spgr.getChildIterator(); + if (it.hasNext()) { + // skip first item + it.next(); + } + for (; it.hasNext();) { + EscherContainerRecord sp = (EscherContainerRecord) it.next(); + HSLFShape sh = HSLFShapeFactory.createShape(sp, null); + sh.setSheet(this); + shapeList.add(sh); + } + + return shapeList; + } + + /** + * @return whether shapes on the master sheet should be shown. By default master graphics is turned off. + * Sheets that support the notion of master (slide, slideLayout) should override it and + * check this setting + */ + public boolean getFollowMasterGraphics() { + return false; + } + + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java new file mode 100644 index 0000000000..6c053d49f4 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java @@ -0,0 +1,452 @@ +/* ==================================================================== + 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 java.awt.Color; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.io.ByteArrayOutputStream; +import java.util.ArrayList; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.exceptions.HSLFException; +import org.apache.poi.hslf.record.*; +import org.apache.poi.sl.draw.geom.*; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.Units; + +/** + * An abstract simple (non-group) shape. + * This is the parent class for all primitive shapes like Line, Rectangle, etc. + * + * @author Yegor Kozlov + */ +public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape { + + public final static double DEFAULT_LINE_WIDTH = 0.75; + + /** + * Records stored in EscherClientDataRecord + */ + protected Record[] _clientRecords; + protected EscherClientDataRecord _clientData; + + /** + * Create a SimpleShape object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected HSLFSimpleShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + } + + /** + * Create a new Shape + * + * @param isChild true if the Line is inside a group, false otherwise + * @return the record container which holds this shape + */ + protected EscherContainerRecord createSpContainer(boolean isChild) { + _escherContainer = new EscherContainerRecord(); + _escherContainer.setRecordId( EscherContainerRecord.SP_CONTAINER ); + _escherContainer.setOptions((short)15); + + EscherSpRecord sp = new EscherSpRecord(); + int flags = EscherSpRecord.FLAG_HAVEANCHOR | EscherSpRecord.FLAG_HASSHAPETYPE; + if (isChild) flags |= EscherSpRecord.FLAG_CHILD; + sp.setFlags(flags); + _escherContainer.addChildRecord(sp); + + EscherOptRecord opt = new EscherOptRecord(); + opt.setRecordId(EscherOptRecord.RECORD_ID); + _escherContainer.addChildRecord(opt); + + EscherRecord anchor; + if(isChild) anchor = new EscherChildAnchorRecord(); + else { + anchor = new EscherClientAnchorRecord(); + + //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); + anchor.fillFields(header, 0, null); + } + _escherContainer.addChildRecord(anchor); + + return _escherContainer; + } + + /** + * Returns width of the line in in points + */ + public double getLineWidth(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH); + double width = (prop == null) ? DEFAULT_LINE_WIDTH : Units.toPoints(prop.getPropertyValue()); + return width; + } + + /** + * Sets the width of line in in points + * @param width the width of line in in points + */ + public void setLineWidth(double width){ + EscherOptRecord opt = getEscherOptRecord(); + setEscherProperty(opt, EscherProperties.LINESTYLE__LINEWIDTH, Units.toEMU(width)); + } + + /** + * Sets the color of line + * + * @param color new color of the line + */ + public void setLineColor(Color color){ + EscherOptRecord opt = getEscherOptRecord(); + if (color == null) { + setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000); + } else { + int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); + setEscherProperty(opt, EscherProperties.LINESTYLE__COLOR, rgb); + setEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH, color == null ? 0x180010 : 0x180018); + } + } + + /** + * @return color of the line. If color is not set returns java.awt.Color.black + */ + public Color getLineColor(){ + EscherOptRecord opt = getEscherOptRecord(); + + EscherSimpleProperty p = getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH); + if(p != null && (p.getPropertyValue() & 0x8) == 0) return null; + + Color clr = getColor(EscherProperties.LINESTYLE__COLOR, EscherProperties.LINESTYLE__OPACITY, -1); + return clr == null ? Color.black : clr; + } + + /** + * Gets line dashing. + * + * @return dashing of the line. + */ + public LineDash getLineDashing(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING); + return (prop == null) ? LineDash.SOLID : LineDash.fromNativeId(prop.getPropertyValue()); + } + + /** + * Sets line dashing. + * + * @param pen new style of the line. + */ + public void setLineDashing(LineDash pen){ + EscherOptRecord opt = getEscherOptRecord(); + setEscherProperty(opt, EscherProperties.LINESTYLE__LINEDASHING, pen == LineDash.SOLID ? -1 : pen.nativeId); + } + + /** + * Gets the line compound style + * + * @return the compound style of the line. + */ + public LineCompound getLineCompound() { + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE); + return (prop == null) ? LineCompound.SINGLE : LineCompound.fromNativeId(prop.getPropertyValue()); + } + + /** + * Sets the line compound style + * + * @param style new compound style of the line. + */ + public void setLineCompound(LineCompound style){ + EscherOptRecord opt = getEscherOptRecord(); + setEscherProperty(opt, EscherProperties.LINESTYLE__LINESTYLE, style == LineCompound.SINGLE ? -1 : style.nativeId); + } + + /** + * Returns line style. One of the constants defined in this class. + * + * @return style of the line. + */ + public StrokeStyle getStrokeStyle(){ + return new StrokeStyle() { + public PaintStyle getPaint() { + return null; + } + + public LineCap getLineCap() { + return null; + } + + public LineDash getLineDash() { + return null; + } + + public LineCompound getLineCompound() { + return null; + } + + public double getLineWidth() { + return 0; + } + + }; + } + + /** + * The color used to fill this shape. + */ + public Color getFillColor(){ + return getFill().getForegroundColor(); + } + + /** + * The color used to fill this shape. + * + * @param color the background color + */ + public void setFillColor(Color color){ + getFill().setForegroundColor(color); + } + + /** + * + * @return 'absolute' anchor of this shape relative to the parent sheet + */ + public Rectangle2D getLogicalAnchor2D(){ + Rectangle2D anchor = getAnchor2D(); + + //if it is a groupped shape see if we need to transform the coordinates + if (getParent() != null){ + ArrayList lst = new ArrayList(); + for (ShapeContainer parent=this.getParent(); + parent instanceof HSLFGroupShape; + parent = ((HSLFGroupShape)parent).getParent()) { + lst.add(0, (HSLFGroupShape)parent); + } + + AffineTransform tx = new AffineTransform(); + for(HSLFGroupShape prnt : lst) { + Rectangle2D exterior = prnt.getAnchor2D(); + Rectangle2D interior = prnt.getCoordinates(); + + double scaleX = exterior.getWidth() / interior.getWidth(); + double scaleY = exterior.getHeight() / interior.getHeight(); + + tx.translate(exterior.getX(), exterior.getY()); + tx.scale(scaleX, scaleY); + tx.translate(-interior.getX(), -interior.getY()); + + } + anchor = tx.createTransformedShape(anchor).getBounds2D(); + } + + double angle = getRotation(); + if(angle != 0.){ + double centerX = anchor.getX() + anchor.getWidth()/2; + double centerY = anchor.getY() + anchor.getHeight()/2; + + AffineTransform trans = new AffineTransform(); + trans.translate(centerX, centerY); + trans.rotate(Math.toRadians(angle)); + trans.translate(-centerX, -centerY); + + Rectangle2D rect = trans.createTransformedShape(anchor).getBounds2D(); + if((anchor.getWidth() < anchor.getHeight() && rect.getWidth() > rect.getHeight()) || + (anchor.getWidth() > anchor.getHeight() && rect.getWidth() < rect.getHeight()) ){ + trans = new AffineTransform(); + trans.translate(centerX, centerY); + trans.rotate(Math.PI/2); + trans.translate(-centerX, -centerY); + anchor = trans.createTransformedShape(anchor).getBounds2D(); + } + } + return anchor; + } + + /** + * Find a record in the underlying EscherClientDataRecord + * + * @param recordType type of the record to search + */ + @SuppressWarnings("unchecked") + protected T getClientDataRecord(int recordType) { + + Record[] records = getClientRecords(); + if(records != null) for (int i = 0; i < records.length; i++) { + if(records[i].getRecordType() == recordType){ + return (T)records[i]; + } + } + return null; + } + + /** + * Search for EscherClientDataRecord, if found, convert its contents into an array of HSLF records + * + * @return an array of HSLF records contained in the shape's EscherClientDataRecord or null + */ + protected Record[] getClientRecords() { + if(_clientData == null){ + EscherRecord r = getEscherChild(EscherClientDataRecord.RECORD_ID); + //ddf can return EscherContainerRecord with recordId=EscherClientDataRecord.RECORD_ID + //convert in to EscherClientDataRecord on the fly + if(r != null && !(r instanceof EscherClientDataRecord)){ + byte[] data = r.serialize(); + r = new EscherClientDataRecord(); + r.fillFields(data, 0, new DefaultEscherRecordFactory()); + } + _clientData = (EscherClientDataRecord)r; + } + if(_clientData != null && _clientRecords == null){ + byte[] data = _clientData.getRemainingData(); + _clientRecords = Record.findChildRecords(data, 0, data.length); + } + return _clientRecords; + } + + protected void updateClientData() { + if(_clientData != null && _clientRecords != null){ + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + for (int i = 0; i < _clientRecords.length; i++) { + _clientRecords[i].writeOut(out); + } + } catch(Exception e){ + throw new HSLFException(e); + } + _clientData.setRemainingData(out.toByteArray()); + } + } + + public void setHyperlink(HSLFHyperlink link){ + if(link.getId() == -1){ + throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first"); + } + + EscherClientDataRecord cldata = new EscherClientDataRecord(); + cldata.setOptions((short)0xF); + getSpContainer().addChildRecord(cldata); // TODO - junit to prove getChildRecords().add is wrong + + InteractiveInfo info = new InteractiveInfo(); + InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); + + switch(link.getType()){ + case HSLFHyperlink.LINK_FIRSTSLIDE: + infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); + infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide); + break; + case HSLFHyperlink.LINK_LASTSLIDE: + infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); + infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide); + break; + case HSLFHyperlink.LINK_NEXTSLIDE: + infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); + infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide); + break; + case HSLFHyperlink.LINK_PREVIOUSSLIDE: + infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP); + infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide); + break; + case HSLFHyperlink.LINK_URL: + infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK); + infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url); + break; + case HSLFHyperlink.LINK_SLIDENUMBER: + infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK); + infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE); + infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber); + break; + } + + infoAtom.setHyperlinkID(link.getId()); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try { + info.writeOut(out); + } catch(Exception e){ + throw new HSLFException(e); + } + cldata.setRemainingData(out.toByteArray()); + + } + + public Guide getAdjustValue(String name) { + if (name == null || !name.matches("adj([1-9]|10)")) { + throw new IllegalArgumentException("Adjust value '"+name+"' not supported."); + } + short escherProp; + switch (Integer.parseInt(name.substring(3))) { + case 1: escherProp = EscherProperties.GEOMETRY__ADJUSTVALUE; break; + case 2: escherProp = EscherProperties.GEOMETRY__ADJUST2VALUE; break; + case 3: escherProp = EscherProperties.GEOMETRY__ADJUST3VALUE; break; + case 4: escherProp = EscherProperties.GEOMETRY__ADJUST4VALUE; break; + case 5: escherProp = EscherProperties.GEOMETRY__ADJUST5VALUE; break; + case 6: escherProp = EscherProperties.GEOMETRY__ADJUST6VALUE; break; + case 7: escherProp = EscherProperties.GEOMETRY__ADJUST7VALUE; break; + case 8: escherProp = EscherProperties.GEOMETRY__ADJUST8VALUE; break; + case 9: escherProp = EscherProperties.GEOMETRY__ADJUST9VALUE; break; + 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); + } + + public LineDecoration getLineDecoration() { + // TODO Auto-generated method stub + return null; + } + + public CustomGeometry getGeometry() { + ShapeType st = getShapeType(); + String name = st.getOoxmlName(); + + PresetGeometries dict = PresetGeometries.getInstance(); + CustomGeometry geom = dict.get(name); + if(geom == null) { + throw new IllegalStateException("Unknown shape geometry: " + name); + } + + return geom; + } + + public Shadow getShadow() { + // TODO Auto-generated method stub + return null; + } + + + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java new file mode 100644 index 0000000000..2fbd5c201f --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java @@ -0,0 +1,480 @@ +/* ==================================================================== + 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 java.util.ArrayList; +import java.util.List; + +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.model.*; +import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; +import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.sl.usermodel.Slide; + +/** + * This class represents a slide in a PowerPoint Document. It allows + * access to the text within, and the layout. For now, it only does + * the text side of things though + * + * @author Nick Burch + * @author Yegor Kozlov + */ + +public final class HSLFSlide extends HSLFSheet implements Slide { + private int _slideNo; + private SlideAtomsSet _atomSet; + private final List> _paragraphs = new ArrayList>(); + private HSLFNotes _notes; // usermodel needs to set this + + /** + * Constructs a Slide from the Slide record, and the SlideAtomsSet + * containing the text. + * Initializes TextRuns, to provide easier access to the text + * + * @param slide the Slide record we're based on + * @param notes the Notes sheet attached to us + * @param atomSet the SlideAtomsSet to get the text from + */ + public HSLFSlide(org.apache.poi.hslf.record.Slide slide, HSLFNotes notes, SlideAtomsSet atomSet, int slideIdentifier, int slideNumber) { + super(slide, slideIdentifier); + + _notes = notes; + _atomSet = atomSet; + _slideNo = slideNumber; + + // For the text coming in from the SlideAtomsSet: + // Build up TextRuns from pairs of TextHeaderAtom and + // one of TextBytesAtom or TextCharsAtom + if (_atomSet != null && _atomSet.getSlideRecords().length > 0) { + List> llhtp = HSLFTextParagraph.findTextParagraphs(_atomSet.getSlideRecords()); + _paragraphs.addAll(llhtp); + if (_paragraphs.isEmpty()) { + throw new RuntimeException("No text records found for slide"); + } + } else { + // No text on the slide, must just be pictures + } + + // Grab text from SlideListWithTexts entries + for(List ltp : _paragraphs) { + for (HSLFTextParagraph tp : ltp) { + tp.supplySheet(this); + } + } + + // Grab the TextRuns from the PPDrawing + List> llOtherRuns = HSLFTextParagraph.findTextParagraphs(getPPDrawing()); + for (List otherRuns : llOtherRuns) { + // Grab text from slide's PPDrawing + for(HSLFTextParagraph tp : otherRuns) { + tp.supplySheet(this); + tp.setIndex(-1); // runs found in PPDrawing are not linked with SlideListWithTexts + } + } + _paragraphs.addAll(llOtherRuns); + } + + /** + * Create a new Slide instance + * @param sheetNumber The internal number of the sheet, as used by PersistPtrHolder + * @param slideNumber The user facing number of the sheet + */ + public HSLFSlide(int sheetNumber, int sheetRefId, int slideNumber){ + super(new org.apache.poi.hslf.record.Slide(), sheetNumber); + _slideNo = slideNumber; + getSheetContainer().setSheetId(sheetRefId); + } + + /** + * Returns the Notes Sheet for this slide, or null if there isn't one + */ + @Override + public HSLFNotes getNotes() { + return _notes; + } + + /** + * Sets the Notes that are associated with this. Updates the + * references in the records to point to the new ID + */ + @Override + public void setNotes(HSLFNotes notes) { + _notes = notes; + + // Update the Slide Atom's ID of where to point to + SlideAtom sa = getSlideRecord().getSlideAtom(); + + if(_notes == null) { + // Set to 0 + sa.setNotesID(0); + } else { + // Set to the value from the notes' sheet id + sa.setNotesID(_notes._getSheetNumber()); + } + } + + /** + * Changes the Slide's (external facing) page number. + * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#reorderSlide(int, int) + */ + public void setSlideNumber(int newSlideNumber) { + _slideNo = newSlideNumber; + } + + /** + * Called by SlideShow ater a new slide is created. + *

    + * For Slide we need to do the following: + *

  • set id of the drawing group. + *
  • set shapeId for the container descriptor and background + *

    + */ + public void onCreate(){ + //initialize drawing group id + EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); + EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0]; + EscherDgRecord dg = (EscherDgRecord) HSLFShape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID); + int dgId = dgg.getMaxDrawingGroupId() + 1; + dg.setOptions((short)(dgId << 4)); + dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1); + dgg.setMaxDrawingGroupId(dgId); + + for (EscherContainerRecord c : dgContainer.getChildContainers()) { + EscherSpRecord spr = null; + switch(c.getRecordId()){ + case EscherContainerRecord.SPGR_CONTAINER: + EscherContainerRecord dc = (EscherContainerRecord)c.getChild(0); + spr = dc.getChildById(EscherSpRecord.RECORD_ID); + break; + case EscherContainerRecord.SP_CONTAINER: + spr = c.getChildById(EscherSpRecord.RECORD_ID); + break; + } + if(spr != null) spr.setShapeId(allocateShapeId()); + } + + //PPT doen't increment the number of saved shapes for group descriptor and background + dg.setNumShapes(1); + } + + /** + * Create a TextBox object that represents the slide's title. + * + * @return TextBox object that represents the slide's title. + */ + public HSLFTextBox addTitle() { + Placeholder pl = new Placeholder(); + pl.setShapeType(ShapeType.RECT); + pl.setRunType(TextHeaderAtom.TITLE_TYPE); + pl.setText("Click to edit title"); + pl.setAnchor(new java.awt.Rectangle(54, 48, 612, 90)); + addShape(pl); + return pl; + } + + + // Complex Accesser methods follow + + /** + * Return title of this slide or null if the slide does not have title. + *

    + * The title is a run of text of type TextHeaderAtom.CENTER_TITLE_TYPE or + * TextHeaderAtom.TITLE_TYPE + *

    + * + * @see TextHeaderAtom + * + * @return title of this slide + */ + public String getTitle(){ + for (List tp : getTextParagraphs()) { + if (tp.isEmpty()) continue; + int type = tp.get(0).getRunType(); + switch (type) { + case TextHeaderAtom.CENTER_TITLE_TYPE: + case TextHeaderAtom.TITLE_TYPE: + String str = HSLFTextParagraph.getRawText(tp); + return HSLFTextParagraph.toExternalString(str, type); + } + } + return null; + } + + // Simple Accesser methods follow + + /** + * Returns an array of all the TextRuns found + */ + public List> getTextParagraphs() { return _paragraphs; } + + /** + * Returns the (public facing) page number of this slide + */ + public int getSlideNumber() { return _slideNo; } + + /** + * Returns the underlying slide record + */ + public org.apache.poi.hslf.record.Slide getSlideRecord() { + return (org.apache.poi.hslf.record.Slide)getSheetContainer(); + } + + /** + * @return set of records inside SlideListWithtext container + * which hold text data for this slide (typically for placeholders). + */ + protected SlideAtomsSet getSlideAtomsSet() { return _atomSet; } + + /** + * Returns master sheet associated with this slide. + * It can be either SlideMaster or TitleMaster objects. + * + * @return the master sheet associated with this slide. + */ + public HSLFMasterSheet getMasterSheet(){ + int masterId = getSlideRecord().getSlideAtom().getMasterID(); + for (HSLFSlideMaster sm : getSlideShow().getSlideMasters()) { + if (masterId == sm._getSheetNumber()) return sm; + } + for (HSLFTitleMaster tm : getSlideShow().getTitleMasters()) { + if (masterId == tm._getSheetNumber()) return tm; + } + return null; + } + + /** + * Change Master of this slide. + */ + public void setMasterSheet(HSLFMasterSheet master){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + int sheetNo = master._getSheetNumber(); + sa.setMasterID(sheetNo); + } + + /** + * Sets whether this slide follows master background + * + * @param flag true if the slide follows master, + * false otherwise + */ + public void setFollowMasterBackground(boolean flag){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + sa.setFollowMasterBackground(flag); + } + + /** + * Whether this slide follows master sheet background + * + * @return true if the slide follows master background, + * false otherwise + */ + public boolean getFollowMasterBackground(){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + return sa.getFollowMasterBackground(); + } + + /** + * Sets whether this slide draws master sheet objects + * + * @param flag true if the slide draws master sheet objects, + * false otherwise + */ + public void setFollowMasterObjects(boolean flag){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + sa.setFollowMasterObjects(flag); + } + + /** + * Whether this slide follows master color scheme + * + * @return true if the slide follows master color scheme, + * false otherwise + */ + public boolean getFollowMasterScheme(){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + return sa.getFollowMasterScheme(); + } + + /** + * Sets whether this slide draws master color scheme + * + * @param flag true if the slide draws master color scheme, + * false otherwise + */ + public void setFollowMasterScheme(boolean flag){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + sa.setFollowMasterScheme(flag); + } + + /** + * Whether this slide draws master sheet objects + * + * @return true if the slide draws master sheet objects, + * false otherwise + */ + public boolean getFollowMasterObjects(){ + SlideAtom sa = getSlideRecord().getSlideAtom(); + return sa.getFollowMasterObjects(); + } + + /** + * Background for this slide. + */ + public HSLFBackground getBackground() { + if(getFollowMasterBackground()) { + return getMasterSheet().getBackground(); + } + return super.getBackground(); + } + + /** + * Color scheme for this slide. + */ + public ColorSchemeAtom getColorScheme() { + if(getFollowMasterScheme()){ + return getMasterSheet().getColorScheme(); + } + return super.getColorScheme(); + } + + /** + * Get the comment(s) for this slide. + * Note - for now, only works on PPT 2000 and + * PPT 2003 files. Doesn't work for PPT 97 + * ones, as they do their comments oddly. + */ + public Comment[] getComments() { + // If there are any, they're in + // ProgTags -> ProgBinaryTag -> BinaryTagData + RecordContainer progTags = (RecordContainer) + getSheetContainer().findFirstOfType( + RecordTypes.ProgTags.typeID + ); + if(progTags != null) { + RecordContainer progBinaryTag = (RecordContainer) + progTags.findFirstOfType( + RecordTypes.ProgBinaryTag.typeID + ); + if(progBinaryTag != null) { + RecordContainer binaryTags = (RecordContainer) + progBinaryTag.findFirstOfType( + RecordTypes.BinaryTagData.typeID + ); + if(binaryTags != null) { + // This is where they'll be + int count = 0; + for(int i=0; i newParas = shape.getTextParagraphs(); + _paragraphs.add(newParas); + } + + /** This will return an atom per TextBox, so if the page has two text boxes the method should return two atoms. */ + public StyleTextProp9Atom[] getNumberedListInfo() { + return this.getPPDrawing().getNumberedListInfo(); + } + + public EscherTextboxWrapper[] getTextboxWrappers() { + return this.getPPDrawing().getTextboxWrappers(); + } + + public void setHidden(boolean hidden) { + org.apache.poi.hslf.record.Slide cont = getSlideRecord(); + + SSSlideInfoAtom slideInfo = + (SSSlideInfoAtom)cont.findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); + if (slideInfo == null) { + slideInfo = new SSSlideInfoAtom(); + cont.addChildAfter(slideInfo, cont.findFirstOfType(RecordTypes.SlideAtom.typeID)); + } + + slideInfo.setEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT, hidden); + } + + public boolean getHidden() { + SSSlideInfoAtom slideInfo = + (SSSlideInfoAtom)getSlideRecord().findFirstOfType(RecordTypes.SSSlideInfoAtom.typeID); + return (slideInfo == null) + ? false + : slideInfo.getEffectTransitionFlagByBit(SSSlideInfoAtom.HIDDEN_BIT); + } + + public boolean getFollowMasterColourScheme() { + // TODO Auto-generated method stub + return false; + } + + public void setFollowMasterColourScheme(boolean follow) { + // TODO Auto-generated method stub + + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java new file mode 100644 index 0000000000..36265735b8 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java @@ -0,0 +1,147 @@ +/* ==================================================================== + 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 java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hslf.model.textproperties.TextProp; +import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.record.*; + +/** + * SlideMaster determines the graphics, layout, and formatting for all the slides in a given presentation. + * It stores information about default font styles, placeholder sizes and positions, + * background design, and color schemes. + * + * @author Yegor Kozlov + */ +public final class HSLFSlideMaster extends HSLFMasterSheet { + private final List> _runs = new ArrayList>(); + + /** + * all TxMasterStyleAtoms available in this master + */ + private TxMasterStyleAtom[] _txmaster; + + /** + * Constructs a SlideMaster from the MainMaster record, + * + */ + public HSLFSlideMaster(MainMaster record, int sheetNo) { + super(record, sheetNo); + + _runs.addAll(HSLFTextParagraph.findTextParagraphs(getPPDrawing())); + for (List p : _runs) { + for (HSLFTextParagraph htp : p) { + htp.supplySheet(this); + } + } + } + + /** + * Returns an array of all the TextRuns found + */ + public List> getTextParagraphs() { + return _runs; + } + + /** + * Returns null since SlideMasters doen't have master sheet. + */ + public HSLFMasterSheet getMasterSheet() { + return null; + } + + /** + * Pickup a style attribute from the master. + * This is the "workhorse" which returns the default style attrubutes. + */ + public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { + + TextProp prop = null; + for (int i = level; i >= 0; i--) { + TextPropCollection[] styles = + isCharacter ? _txmaster[txtype].getCharacterStyles() : _txmaster[txtype].getParagraphStyles(); + if (i < styles.length) prop = styles[i].findByName(name); + if (prop != null) break; + } + if (prop == null) { + if(isCharacter) { + switch (txtype) { + case TextHeaderAtom.CENTRE_BODY_TYPE: + case TextHeaderAtom.HALF_BODY_TYPE: + case TextHeaderAtom.QUARTER_BODY_TYPE: + txtype = TextHeaderAtom.BODY_TYPE; + break; + case TextHeaderAtom.CENTER_TITLE_TYPE: + txtype = TextHeaderAtom.TITLE_TYPE; + break; + default: + return null; + } + } else { + switch (txtype) { + case TextHeaderAtom.CENTRE_BODY_TYPE: + case TextHeaderAtom.HALF_BODY_TYPE: + case TextHeaderAtom.QUARTER_BODY_TYPE: + txtype = TextHeaderAtom.BODY_TYPE; + break; + case TextHeaderAtom.CENTER_TITLE_TYPE: + txtype = TextHeaderAtom.TITLE_TYPE; + break; + default: + return null; + } + } + prop = getStyleAttribute(txtype, level, name, isCharacter); + } + return prop; + } + + /** + * Assign SlideShow for this slide master. + * (Used interanlly) + */ + public void setSlideShow(HSLFSlideShow ss) { + super.setSlideShow(ss); + + //after the slide show is assigned collect all available style records + if (_txmaster == null) { + _txmaster = new TxMasterStyleAtom[9]; + + TxMasterStyleAtom txdoc = getSlideShow().getDocumentRecord().getEnvironment().getTxMasterStyleAtom(); + _txmaster[txdoc.getTextType()] = txdoc; + + TxMasterStyleAtom[] txrec = ((MainMaster)getSheetContainer()).getTxMasterStyleAtoms(); + for (int i = 0; i < txrec.length; i++) { + int txType = txrec[i].getTextType(); + if(_txmaster[txType] == null) _txmaster[txType] = txrec[i]; + } + } + } + + protected void onAddTextShape(HSLFTextShape shape) { + List runs = shape.getTextParagraphs(); + _runs.add(runs); + } + + public TxMasterStyleAtom[] getTxMasterStyleAtoms(){ + return _txmaster; + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java index 1f9f6ca027..cf91e56953 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java @@ -25,12 +25,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherContainerRecord; @@ -69,7 +64,7 @@ import org.apache.poi.hslf.record.SlidePersistAtom; import org.apache.poi.hslf.record.UserEditAtom; import org.apache.poi.poifs.filesystem.DirectoryNode; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.sl.usermodel.SlideShow; +import org.apache.poi.sl.usermodel.*; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; @@ -97,10 +92,10 @@ public final class HSLFSlideShow implements SlideShow { private Document _documentRecord; // Friendly objects for people to deal with - private SlideMaster[] _masters; - private TitleMaster[] _titleMasters; - private HSLFSlide[] _slides; - private HSLFNotes[] _notes; + private final List _masters = new ArrayList(); + private final List _titleMasters = new ArrayList(); + private final List _slides = new ArrayList(); + private final List _notes = new ArrayList(); private FontCollection _fonts; // For logging @@ -310,27 +305,21 @@ public final class HSLFSlideShow implements SlideShow { if (masterSLWT != null) { masterSets = masterSLWT.getSlideAtomsSets(); - ArrayList mmr = new ArrayList(); - ArrayList tmr = new ArrayList(); - for (SlideAtomsSet sas : masterSets) { Record r = getCoreRecordForSAS(sas); int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier(); if (r instanceof org.apache.poi.hslf.record.Slide) { - TitleMaster master = new TitleMaster((org.apache.poi.hslf.record.Slide) r, + HSLFTitleMaster master = new HSLFTitleMaster((org.apache.poi.hslf.record.Slide) r, sheetNo); master.setSlideShow(this); - tmr.add(master); + _titleMasters.add(master); } else if (r instanceof org.apache.poi.hslf.record.MainMaster) { - SlideMaster master = new SlideMaster((org.apache.poi.hslf.record.MainMaster) r, + HSLFSlideMaster master = new HSLFSlideMaster((org.apache.poi.hslf.record.MainMaster) r, sheetNo); master.setSlideShow(this); - mmr.add(master); + _masters.add(master); } } - - _masters = mmr.toArray(new SlideMaster[mmr.size()]); - _titleMasters = tmr.toArray(new TitleMaster[tmr.size()]); } // Having sorted out the masters, that leaves the notes and slides @@ -408,16 +397,14 @@ public final class HSLFSlideShow implements SlideShow { // Finally, generate model objects for everything // Notes first - _notes = new HSLFNotes[notesRecords.length]; - for (int i = 0; i < _notes.length; i++) { - if (notesRecords[i] != null) { - _notes[i] = new HSLFNotes(notesRecords[i]); - _notes[i].setSlideShow(this); - } + for (org.apache.poi.hslf.record.Notes n : notesRecords) { + if (n == null) continue; + HSLFNotes hn = new HSLFNotes(n); + hn.setSlideShow(this); + _notes.add(hn); } // Then slides - _slides = new HSLFSlide[slidesRecords.length]; - for (int i = 0; i < _slides.length; i++) { + for (int i = 0; i < slidesRecords.length; i++) { SlideAtomsSet sas = slidesSets[i]; int slideIdentifier = sas.getSlidePersistAtom().getSlideIdentifier(); @@ -429,15 +416,16 @@ public final class HSLFSlideShow implements SlideShow { if (noteId != 0) { Integer notesPos = slideIdToNotes.get(noteId); if (notesPos != null) { - notes = _notes[notesPos]; + notes = _notes.get(notesPos); } else { logger.log(POILogger.ERROR, "Notes not found for noteId=" + noteId); } } // Now, build our slide - _slides[i] = new HSLFSlide(slidesRecords[i], notes, sas, slideIdentifier, (i + 1)); - _slides[i].setSlideShow(this); + HSLFSlide hs = new HSLFSlide(slidesRecords[i], notes, sas, slideIdentifier, (i + 1)); + hs.setSlideShow(this); + _slides.add(hs); } } @@ -472,28 +460,30 @@ public final class HSLFSlideShow implements SlideShow { /** * Returns an array of all the normal Slides found in the slideshow */ - public HSLFSlide[] getSlides() { + @Override + public List getSlides() { return _slides; } /** * Returns an array of all the normal Notes found in the slideshow */ - public HSLFNotes[] getNotes() { + public List getNotes() { return _notes; } /** * Returns an array of all the normal Slide Masters found in the slideshow */ - public SlideMaster[] getSlidesMasters() { + @Override + public List getSlideMasters() { return _masters; } - + /** * Returns an array of all the normal Title Masters found in the slideshow */ - public TitleMaster[] getTitleMasters() { + public List getTitleMasters() { return _titleMasters; } @@ -573,12 +563,16 @@ public final class HSLFSlideShow implements SlideShow { if (oldSlideNumber < 1 || newSlideNumber < 1) { throw new IllegalArgumentException("Old and new slide numbers must be greater than 0"); } - if (oldSlideNumber > _slides.length || newSlideNumber > _slides.length) { + if (oldSlideNumber > _slides.size() || newSlideNumber > _slides.size()) { throw new IllegalArgumentException( "Old and new slide numbers must not exceed the number of slides (" - + _slides.length + ")"); + + _slides.size() + ")"); } + _slides.get(newSlideNumber).setSlideNumber(oldSlideNumber); + _slides.get(oldSlideNumber).setSlideNumber(newSlideNumber); + Collections.swap(_slides, oldSlideNumber-1, newSlideNumber-1); + // The order of slides is defined by the order of slide atom sets in the // SlideListWithText container. SlideListWithText slwt = _documentRecord.getSlideSlideListWithText(); @@ -589,13 +583,9 @@ public final class HSLFSlideShow implements SlideShow { sas[newSlideNumber - 1] = tmp; ArrayList lst = new ArrayList(); - for (int i = 0; i < sas.length; i++) { - lst.add(sas[i].getSlidePersistAtom()); - Record[] r = sas[i].getSlideRecords(); - for (int j = 0; j < r.length; j++) { - lst.add(r[j]); - } - _slides[i].setSlideNumber(i + 1); + for (SlideAtomsSet s : sas) { + lst.add(s.getSlidePersistAtom()); + lst.addAll(Arrays.asList(s.getSlideRecords())); } Record[] r = lst.toArray(new Record[lst.size()]); slwt.setChildRecord(r); @@ -613,7 +603,7 @@ public final class HSLFSlideShow implements SlideShow { * @return the slide that was removed from the slide show. */ public HSLFSlide removeSlide(int index) { - int lastSlideIdx = _slides.length - 1; + int lastSlideIdx = _slides.size() - 1; if (index < 0 || index > lastSlideIdx) { throw new IllegalArgumentException("Slide index (" + index + ") is out of range (0.." + lastSlideIdx + ")"); @@ -622,26 +612,19 @@ public final class HSLFSlideShow implements SlideShow { SlideListWithText slwt = _documentRecord.getSlideSlideListWithText(); SlideAtomsSet[] sas = slwt.getSlideAtomsSets(); - HSLFSlide removedSlide = null; - ArrayList records = new ArrayList(); - ArrayList sa = new ArrayList(); - ArrayList sl = new ArrayList(); - - ArrayList nt = new ArrayList(); - for (HSLFNotes notes : getNotes()) - nt.add(notes); - - for (int i = 0, num = 0; i < _slides.length; i++) { - if (i != index) { - sl.add(_slides[i]); - sa.add(sas[i]); - _slides[i].setSlideNumber(num++); - records.add(sas[i].getSlidePersistAtom()); - records.addAll(Arrays.asList(sas[i].getSlideRecords())); - } else { - removedSlide = _slides[i]; - nt.remove(_slides[i].getNotesSheet()); - } + List records = new ArrayList(); + List sa = Arrays.asList(sas); + + HSLFSlide removedSlide = _slides.remove(index); + _notes.remove(removedSlide.getNotes()); + sa.remove(index); + + int i=0; + for (HSLFSlide s : _slides) s.setSlideNumber(i++); + + for (SlideAtomsSet s : sa) { + records.add(s.getSlidePersistAtom()); + records.addAll(Arrays.asList(s.getSlideRecords())); } if (sa.size() == 0) { _documentRecord.removeSlideListWithText(slwt); @@ -649,34 +632,29 @@ public final class HSLFSlideShow implements SlideShow { slwt.setSlideAtomsSets(sa.toArray(new SlideAtomsSet[sa.size()])); slwt.setChildRecord(records.toArray(new Record[records.size()])); } - _slides = sl.toArray(new HSLFSlide[sl.size()]); // if the removed slide had notes - remove references to them too - if (removedSlide != null) { - int notesId = removedSlide.getSlideRecord().getSlideAtom().getNotesID(); - if (notesId != 0) { - SlideListWithText nslwt = _documentRecord.getNotesSlideListWithText(); - records = new ArrayList(); - ArrayList na = new ArrayList(); - for (SlideAtomsSet ns : nslwt.getSlideAtomsSets()) { - if (ns.getSlidePersistAtom().getSlideIdentifier() != notesId) { - na.add(ns); - records.add(ns.getSlidePersistAtom()); - if (ns.getSlideRecords() != null) - records.addAll(Arrays.asList(ns.getSlideRecords())); - } - } - if (na.size() == 0) { - _documentRecord.removeSlideListWithText(nslwt); - } else { - nslwt.setSlideAtomsSets(na.toArray(new SlideAtomsSet[na.size()])); - nslwt.setChildRecord(records.toArray(new Record[records.size()])); + int notesId = (removedSlide != null) ? removedSlide.getSlideRecord().getSlideAtom().getNotesID() : 0; + if (notesId != 0) { + SlideListWithText nslwt = _documentRecord.getNotesSlideListWithText(); + records = new ArrayList(); + ArrayList na = new ArrayList(); + for (SlideAtomsSet ns : nslwt.getSlideAtomsSets()) { + if (ns.getSlidePersistAtom().getSlideIdentifier() == notesId) continue; + na.add(ns); + records.add(ns.getSlidePersistAtom()); + if (ns.getSlideRecords() != null) { + records.addAll(Arrays.asList(ns.getSlideRecords())); } - + } + if (na.isEmpty()) { + _documentRecord.removeSlideListWithText(nslwt); + } else { + nslwt.setSlideAtomsSets(na.toArray(new SlideAtomsSet[na.size()])); + nslwt.setChildRecord(records.toArray(new Record[records.size()])); } } - _notes = nt.toArray(new HSLFNotes[nt.size()]); return removedSlide; } @@ -736,16 +714,13 @@ public final class HSLFSlideShow implements SlideShow { slist.addSlidePersistAtom(sp); // Create a new Slide - HSLFSlide slide = new HSLFSlide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length + 1); + HSLFSlide slide = new HSLFSlide(sp.getSlideIdentifier(), sp.getRefID(), _slides.size() + 1); slide.setSlideShow(this); slide.onCreate(); // Add in to the list of Slides - HSLFSlide[] s = new HSLFSlide[_slides.length + 1]; - System.arraycopy(_slides, 0, s, 0, _slides.length); - s[_slides.length] = slide; - _slides = s; - logger.log(POILogger.INFO, "Added slide " + _slides.length + " with ref " + sp.getRefID() + _slides.add(slide); + logger.log(POILogger.INFO, "Added slide " + _slides.size() + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier()); // Add the core records for this new Slide to the record tree @@ -754,7 +729,7 @@ public final class HSLFSlideShow implements SlideShow { sp.setRefID(psrId); slideRecord.setSheetId(psrId); - slide.setMasterSheet(_masters[0]); + slide.setMasterSheet(_masters.get(0)); // All done and added return slide; } @@ -901,7 +876,7 @@ public final class HSLFSlideShow implements SlideShow { */ public HeadersFooters getSlideHeadersFooters() { // detect if this ppt was saved in Office2007 - String tag = getSlidesMasters()[0].getProgrammableTag(); + String tag = getSlideMasters().get(0).getProgrammableTag(); boolean ppt2007 = "___PPT12".equals(tag); HeadersFootersContainer hdd = null; @@ -927,7 +902,7 @@ public final class HSLFSlideShow implements SlideShow { */ public HeadersFooters getNotesHeadersFooters() { // detect if this ppt was saved in Office2007 - String tag = getSlidesMasters()[0].getProgrammableTag(); + String tag = getSlideMasters().get(0).getProgrammableTag(); boolean ppt2007 = "___PPT12".equals(tag); HeadersFootersContainer hdd = null; @@ -943,8 +918,8 @@ public final class HSLFSlideShow implements SlideShow { hdd = new HeadersFootersContainer(HeadersFootersContainer.NotesHeadersFootersContainer); newRecord = true; } - if (ppt2007 && _notes.length > 0) { - return new HeadersFooters(hdd, _notes[0], newRecord, ppt2007); + if (ppt2007 && !_notes.isEmpty()) { + return new HeadersFooters(hdd, _notes.get(0), newRecord, ppt2007); } return new HeadersFooters(hdd, this, newRecord, ppt2007); } @@ -1010,10 +985,10 @@ public final class HSLFSlideShow implements SlideShow { * * @return 0-based index of the hyperlink */ - public int addHyperlink(Hyperlink link) { + public int addHyperlink(HSLFHyperlink link) { ExHyperlink ctrl = new ExHyperlink(); ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom(); - if(link.getType() == Hyperlink.LINK_SLIDENUMBER) { + if(link.getType() == HSLFHyperlink.LINK_SLIDENUMBER) { ctrl.setLinkURL(link.getAddress(), 0x30); } else { ctrl.setLinkURL(link.getAddress()); @@ -1160,4 +1135,15 @@ public final class HSLFSlideShow implements SlideShow { return psrId; } + + public MasterSheet createMasterSheet() + throws IOException { + // TODO Auto-generated method stub + return null; + } + + public Resources getResources() { + // TODO Auto-generated method stub + return null; + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowEncrypted.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowEncrypted.java new file mode 100644 index 0000000000..30397bfab8 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowEncrypted.java @@ -0,0 +1,494 @@ +/* ==================================================================== + 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 java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.TreeMap; + +import javax.crypto.Cipher; +import javax.crypto.CipherOutputStream; + +import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; +import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException; +import org.apache.poi.hslf.record.DocumentEncryptionAtom; +import org.apache.poi.hslf.record.PersistPtrHolder; +import org.apache.poi.hslf.record.PositionDependentRecord; +import org.apache.poi.hslf.record.Record; +import org.apache.poi.hslf.record.UserEditAtom; +import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; +import org.apache.poi.poifs.crypt.Decryptor; +import org.apache.poi.poifs.crypt.EncryptionInfo; +import org.apache.poi.poifs.crypt.Encryptor; +import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIDecryptor; +import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptor; +import org.apache.poi.util.BitField; +import org.apache.poi.util.Internal; +import org.apache.poi.util.LittleEndian; + +/** + * This class provides helper functions for encrypted PowerPoint documents. + */ +@Internal +public class HSLFSlideShowEncrypted { + DocumentEncryptionAtom dea; + CryptoAPIEncryptor enc = null; + CryptoAPIDecryptor dec = null; + Cipher cipher = null; + CipherOutputStream cyos = null; + + private static final BitField fieldRecInst = new BitField(0xFFF0); + + protected HSLFSlideShowEncrypted(DocumentEncryptionAtom dea) { + this.dea = dea; + } + + protected HSLFSlideShowEncrypted(byte[] docstream, NavigableMap recordMap) { + // check for DocumentEncryptionAtom, which would be at the last offset + // need to ignore already set UserEdit and PersistAtoms + UserEditAtom userEditAtomWithEncryption = null; + for (Map.Entry me : recordMap.descendingMap().entrySet()) { + Record r = me.getValue(); + if (!(r instanceof UserEditAtom)) continue; + UserEditAtom uea = (UserEditAtom)r; + if (uea.getEncryptSessionPersistIdRef() != -1) { + userEditAtomWithEncryption = uea; + break; + } + } + + if (userEditAtomWithEncryption == null) { + dea = null; + return; + } + + Record r = recordMap.get(userEditAtomWithEncryption.getPersistPointersOffset()); + assert(r instanceof PersistPtrHolder); + PersistPtrHolder ptr = (PersistPtrHolder)r; + + Integer encOffset = ptr.getSlideLocationsLookup().get(userEditAtomWithEncryption.getEncryptSessionPersistIdRef()); + assert(encOffset != null); + + r = recordMap.get(encOffset); + if (r == null) { + r = Record.buildRecordAtOffset(docstream, encOffset); + recordMap.put(encOffset, r); + } + assert(r instanceof DocumentEncryptionAtom); + this.dea = (DocumentEncryptionAtom)r; + + CryptoAPIDecryptor dec = (CryptoAPIDecryptor)dea.getEncryptionInfo().getDecryptor(); + String pass = Biff8EncryptionKey.getCurrentUserPassword(); + if(!dec.verifyPassword(pass != null ? pass : Decryptor.DEFAULT_PASSWORD)) { + throw new EncryptedPowerPointFileException("PowerPoint file is encrypted. The correct password needs to be set via Biff8EncryptionKey.setCurrentUserPassword()"); + } + } + + public DocumentEncryptionAtom getDocumentEncryptionAtom() { + return dea; + } + + protected void setPersistId(int persistId) { + if (enc != null && dec != null) { + throw new EncryptedPowerPointFileException("Use instance either for en- or decryption"); + } + + try { + if (enc != null) cipher = enc.initCipherForBlock(cipher, persistId); + if (dec != null) cipher = dec.initCipherForBlock(cipher, persistId); + } catch (GeneralSecurityException e) { + throw new EncryptedPowerPointFileException(e); + } + } + + protected void decryptInit() { + if (dec != null) return; + EncryptionInfo ei = dea.getEncryptionInfo(); + dec = (CryptoAPIDecryptor)ei.getDecryptor(); + } + + protected void encryptInit() { + if (enc != null) return; + EncryptionInfo ei = dea.getEncryptionInfo(); + enc = (CryptoAPIEncryptor)ei.getEncryptor(); + } + + + + protected OutputStream encryptRecord(OutputStream plainStream, int persistId, Record record) { + boolean isPlain = (dea == null + || record instanceof UserEditAtom + || record instanceof PersistPtrHolder + || record instanceof DocumentEncryptionAtom + ); + if (isPlain) return plainStream; + + encryptInit(); + setPersistId(persistId); + + if (cyos == null) { + cyos = new CipherOutputStream(plainStream, cipher); + } + return cyos; + } + + protected void decryptRecord(byte[] docstream, int persistId, int offset) { + if (dea == null) return; + + decryptInit(); + setPersistId(persistId); + + try { + // decrypt header and read length to be decrypted + cipher.update(docstream, offset, 8, docstream, offset); + // decrypt the rest of the record + int rlen = (int)LittleEndian.getUInt(docstream, offset+4); + cipher.update(docstream, offset+8, rlen, docstream, offset+8); + } catch (GeneralSecurityException e) { + throw new CorruptPowerPointFileException(e); + } + } + + protected void decryptPicture(byte[] pictstream, int offset) { + if (dea == null) return; + + decryptInit(); + setPersistId(0); + + try { + // decrypt header and read length to be decrypted + cipher.doFinal(pictstream, offset, 8, pictstream, offset); + int recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); + int recType = LittleEndian.getUShort(pictstream, offset+2); + int rlen = (int)LittleEndian.getUInt(pictstream, offset+4); + offset += 8; + int endOffset = offset + rlen; + + if (recType == 0xF007) { + // TOOD: get a real example file ... to actual test the FBSE entry + // not sure where the foDelay block is + + // File BLIP Store Entry (FBSE) + cipher.doFinal(pictstream, offset, 1, pictstream, offset); // btWin32 + offset++; + cipher.doFinal(pictstream, offset, 1, pictstream, offset); // btMacOS + offset++; + cipher.doFinal(pictstream, offset, 16, pictstream, offset); // rgbUid + offset += 16; + cipher.doFinal(pictstream, offset, 2, pictstream, offset); // tag + offset += 2; + cipher.doFinal(pictstream, offset, 4, pictstream, offset); // size + offset += 4; + cipher.doFinal(pictstream, offset, 4, pictstream, offset); // cRef + offset += 4; + cipher.doFinal(pictstream, offset, 4, pictstream, offset); // foDelay + offset += 4; + cipher.doFinal(pictstream, offset+0, 1, pictstream, offset+0); // unused1 + cipher.doFinal(pictstream, offset+1, 1, pictstream, offset+1); // cbName + cipher.doFinal(pictstream, offset+2, 1, pictstream, offset+2); // unused2 + cipher.doFinal(pictstream, offset+3, 1, pictstream, offset+3); // unused3 + int cbName = LittleEndian.getUShort(pictstream, offset+1); + offset += 4; + if (cbName > 0) { + cipher.doFinal(pictstream, offset, cbName, pictstream, offset); // nameData + offset += cbName; + } + if (offset == endOffset) { + return; // no embedded blip + } + // fall through, read embedded blip now + + // update header data + cipher.doFinal(pictstream, offset, 8, pictstream, offset); + recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); + recType = LittleEndian.getUShort(pictstream, offset+2); + rlen = (int)LittleEndian.getUInt(pictstream, offset+4); + offset += 8; + } + + int rgbUidCnt = (recInst == 0x217 || recInst == 0x3D5 || recInst == 0x46B || recInst == 0x543 || + recInst == 0x6E1 || recInst == 0x6E3 || recInst == 0x6E5 || recInst == 0x7A9) ? 2 : 1; + + for (int i=0; i 0) { + cipher.doFinal(pictstream, offset, cbName, pictstream, offset); // nameData + offset += cbName; + } + if (offset == endOffset) { + return; // no embedded blip + } + // fall through, read embedded blip now + + // update header data + recInst = fieldRecInst.getValue(LittleEndian.getUShort(pictstream, offset)); + recType = LittleEndian.getUShort(pictstream, offset+2); + rlen = (int)LittleEndian.getUInt(pictstream, offset+4); + cipher.doFinal(pictstream, offset, 8, pictstream, offset); + offset += 8; + } + + int rgbUidCnt = (recInst == 0x217 || recInst == 0x3D5 || recInst == 0x46B || recInst == 0x543 || + recInst == 0x6E1 || recInst == 0x6E3 || recInst == 0x6E5 || recInst == 0x7A9) ? 2 : 1; + + for (int i=0; i done + return records; + } else { + // need to remove password data + dea = null; + return removeEncryptionRecord(records); + } + } else { + // create password record + if (dea == null) { + dea = new DocumentEncryptionAtom(); + } + EncryptionInfo ei = dea.getEncryptionInfo(); + byte salt[] = ei.getVerifier().getSalt(); + Encryptor enc = ei.getEncryptor(); + if (salt == null) { + enc.confirmPassword(password); + } else { + byte verifier[] = ei.getDecryptor().getVerifier(); + enc.confirmPassword(password, null, null, verifier, salt, null); + } + + // move EncryptionRecord to last slide position + records = normalizeRecords(records); + return addEncryptionRecord(records, dea); + } + } + + /** + * remove duplicated UserEditAtoms and merge PersistPtrHolder. + * Before this method is called, make sure that the offsets are correct, + * i.e. call {@link HSLFSlideShowImpl#updateAndWriteDependantRecords(OutputStream, Map)} + */ + protected static Record[] normalizeRecords(Record records[]) { + // http://msdn.microsoft.com/en-us/library/office/gg615594(v=office.14).aspx + // repeated slideIds can be overwritten, i.e. ignored + + UserEditAtom uea = null; + PersistPtrHolder pph = null; + TreeMap slideLocations = new TreeMap(); + TreeMap recordMap = new TreeMap(); + List obsoleteOffsets = new ArrayList(); + int duplicatedCount = 0; + for (Record r : records) { + assert(r instanceof PositionDependentRecord); + PositionDependentRecord pdr = (PositionDependentRecord)r; + if (pdr instanceof UserEditAtom) { + uea = (UserEditAtom)pdr; + continue; + } + + if (pdr instanceof PersistPtrHolder) { + if (pph != null) { + duplicatedCount++; + } + pph = (PersistPtrHolder)pdr; + for (Map.Entry me : pph.getSlideLocationsLookup().entrySet()) { + Integer oldOffset = slideLocations.put(me.getKey(), me.getValue()); + if (oldOffset != null) obsoleteOffsets.add(oldOffset); + } + continue; + } + + recordMap.put(pdr.getLastOnDiskOffset(), r); + } + recordMap.put(pph.getLastOnDiskOffset(), pph); + recordMap.put(uea.getLastOnDiskOffset(), uea); + + assert(uea != null && pph != null && uea.getPersistPointersOffset() == pph.getLastOnDiskOffset()); + + if (duplicatedCount == 0 && obsoleteOffsets.isEmpty()) { + return records; + } + + uea.setLastUserEditAtomOffset(0); + pph.clear(); + for (Map.Entry me : slideLocations.entrySet()) { + pph.addSlideLookup(me.getKey(), me.getValue()); + } + + for (Integer oldOffset : obsoleteOffsets) { + recordMap.remove(oldOffset); + } + + return recordMap.values().toArray(new Record[recordMap.size()]); + } + + + protected static Record[] removeEncryptionRecord(Record records[]) { + int deaSlideId = -1; + int deaOffset = -1; + PersistPtrHolder ptr = null; + UserEditAtom uea = null; + List recordList = new ArrayList(); + for (Record r : records) { + if (r instanceof DocumentEncryptionAtom) { + deaOffset = ((DocumentEncryptionAtom)r).getLastOnDiskOffset(); + continue; + } else if (r instanceof UserEditAtom) { + uea = (UserEditAtom)r; + deaSlideId = uea.getEncryptSessionPersistIdRef(); + uea.setEncryptSessionPersistIdRef(-1); + } else if (r instanceof PersistPtrHolder) { + ptr = (PersistPtrHolder)r; + } + recordList.add(r); + } + + assert(ptr != null); + if (deaSlideId == -1 && deaOffset == -1) return records; + + TreeMap tm = new TreeMap(ptr.getSlideLocationsLookup()); + ptr.clear(); + int maxSlideId = -1; + for (Map.Entry me : tm.entrySet()) { + if (me.getKey() == deaSlideId || me.getValue() == deaOffset) continue; + ptr.addSlideLookup(me.getKey(), me.getValue()); + maxSlideId = Math.max(me.getKey(), maxSlideId); + } + + uea.setMaxPersistWritten(maxSlideId); + + records = recordList.toArray(new Record[recordList.size()]); + + return records; + } + + + protected static Record[] addEncryptionRecord(Record records[], DocumentEncryptionAtom dea) { + assert(dea != null); + int ueaIdx = -1, ptrIdx = -1, deaIdx = -1, idx = -1; + for (Record r : records) { + idx++; + if (r instanceof UserEditAtom) ueaIdx = idx; + else if (r instanceof PersistPtrHolder) ptrIdx = idx; + else if (r instanceof DocumentEncryptionAtom) deaIdx = idx; + } + assert(ueaIdx != -1 && ptrIdx != -1 && ptrIdx < ueaIdx); + if (deaIdx != -1) { + DocumentEncryptionAtom deaOld = (DocumentEncryptionAtom)records[deaIdx]; + dea.setLastOnDiskOffset(deaOld.getLastOnDiskOffset()); + records[deaIdx] = dea; + return records; + } else { + PersistPtrHolder ptr = (PersistPtrHolder)records[ptrIdx]; + UserEditAtom uea = ((UserEditAtom)records[ueaIdx]); + dea.setLastOnDiskOffset(ptr.getLastOnDiskOffset()-1); + int nextSlideId = uea.getMaxPersistWritten()+1; + ptr.addSlideLookup(nextSlideId, ptr.getLastOnDiskOffset()-1); + uea.setEncryptSessionPersistIdRef(nextSlideId); + uea.setMaxPersistWritten(nextSlideId); + + Record newRecords[] = new Record[records.length+1]; + if (ptrIdx > 0) System.arraycopy(records, 0, newRecords, 0, ptrIdx); + if (ptrIdx < records.length-1) System.arraycopy(records, ptrIdx, newRecords, ptrIdx+1, records.length-ptrIdx); + newRecords[ptrIdx] = dea; + return newRecords; + } + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java new file mode 100644 index 0000000000..ec5f735d17 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShowImpl.java @@ -0,0 +1,806 @@ +/* ==================================================================== + 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 java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.List; +import java.util.Map; +import java.util.NavigableMap; +import java.util.TreeMap; + +import org.apache.poi.POIDocument; +import org.apache.poi.hpsf.PropertySet; +import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException; +import org.apache.poi.hslf.exceptions.HSLFException; +import org.apache.poi.hslf.record.CurrentUserAtom; +import org.apache.poi.hslf.record.DocumentEncryptionAtom; +import org.apache.poi.hslf.record.ExOleObjStg; +import org.apache.poi.hslf.record.PersistPtrHolder; +import org.apache.poi.hslf.record.PersistRecord; +import org.apache.poi.hslf.record.PositionDependentRecord; +import org.apache.poi.hslf.record.Record; +import org.apache.poi.hslf.record.RecordTypes; +import org.apache.poi.hslf.record.UserEditAtom; +import org.apache.poi.poifs.crypt.cryptoapi.CryptoAPIEncryptor; +import org.apache.poi.poifs.filesystem.DirectoryNode; +import org.apache.poi.poifs.filesystem.DocumentEntry; +import org.apache.poi.poifs.filesystem.DocumentInputStream; +import org.apache.poi.poifs.filesystem.EntryUtils; +import org.apache.poi.poifs.filesystem.NPOIFSFileSystem; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * This class contains the main functionality for the Powerpoint file + * "reader". It is only a very basic class for now + * + * @author Nick Burch + */ +public final class HSLFSlideShowImpl extends POIDocument { + public static final int UNSET_OFFSET = -1; + + // For logging + private POILogger logger = POILogFactory.getLogger(this.getClass()); + + // Holds metadata on where things are in our document + private CurrentUserAtom currentUser; + + // Low level contents of the file + private byte[] _docstream; + + // Low level contents + private Record[] _records; + + // Raw Pictures contained in the pictures stream + private List _pictures; + + // Embedded objects stored in storage records in the document stream, lazily populated. + private HSLFObjectData[] _objects; + + /** + * Returns the underlying POIFSFileSystem for the document + * that is open. + */ + protected POIFSFileSystem getPOIFSFileSystem() { + return directory.getFileSystem(); + } + + /** + * Returns the directory in the underlying POIFSFileSystem for the + * document that is open. + */ + protected DirectoryNode getPOIFSDirectory() { + return directory; + } + + /** + * Constructs a Powerpoint document from fileName. Parses the document + * and places all the important stuff into data structures. + * + * @param fileName The name of the file to read. + * @throws IOException if there is a problem while parsing the document. + */ + public HSLFSlideShowImpl(String fileName) throws IOException + { + this(new FileInputStream(fileName)); + } + + /** + * Constructs a Powerpoint document from an input stream. Parses the + * document and places all the important stuff into data structures. + * + * @param inputStream the source of the data + * @throws IOException if there is a problem while parsing the document. + */ + public HSLFSlideShowImpl(InputStream inputStream) throws IOException { + //do Ole stuff + this(new POIFSFileSystem(inputStream)); + } + + /** + * Constructs a Powerpoint document from a POIFS Filesystem. Parses the + * document and places all the important stuff into data structures. + * + * @param filesystem the POIFS FileSystem to read from + * @throws IOException if there is a problem while parsing the document. + */ + public HSLFSlideShowImpl(POIFSFileSystem filesystem) throws IOException + { + this(filesystem.getRoot()); + } + + /** + * Constructs a Powerpoint document from a POIFS Filesystem. Parses the + * document and places all the important stuff into data structures. + * + * @param filesystem the POIFS FileSystem to read from + * @throws IOException if there is a problem while parsing the document. + */ + public HSLFSlideShowImpl(NPOIFSFileSystem filesystem) throws IOException + { + this(filesystem.getRoot()); + } + + /** + * Constructs a Powerpoint document from a specific point in a + * POIFS Filesystem. Parses the document and places all the + * important stuff into data structures. + * + * @deprecated Use {@link #HSLFSlideShow(DirectoryNode)} instead + * @param dir the POIFS directory to read from + * @param filesystem the POIFS FileSystem to read from + * @throws IOException if there is a problem while parsing the document. + */ + @Deprecated + public HSLFSlideShowImpl(DirectoryNode dir, POIFSFileSystem filesystem) throws IOException + { + this(dir); + } + + /** + * Constructs a Powerpoint document from a specific point in a + * POIFS Filesystem. Parses the document and places all the + * important stuff into data structures. + * + * @param dir the POIFS directory to read from + * @throws IOException if there is a problem while parsing the document. + */ + public HSLFSlideShowImpl(DirectoryNode dir) throws IOException { + super(handleDualStorage(dir)); + + // First up, grab the "Current User" stream + // We need this before we can detect Encrypted Documents + readCurrentUserStream(); + + // Next up, grab the data that makes up the + // PowerPoint stream + readPowerPointStream(); + + // Now, build records based on the PowerPoint stream + buildRecords(); + + // Look for any other streams + readOtherStreams(); + } + + private static DirectoryNode handleDualStorage(DirectoryNode dir) throws IOException { + // when there's a dual storage entry, use it, as the outer document can't be read quite probably ... + String dualName = "PP97_DUALSTORAGE"; + if (!dir.hasEntry(dualName)) return dir; + dir = (DirectoryNode)dir.getEntry(dualName); + return dir; + } + + /** + * Constructs a new, empty, Powerpoint document. + */ + public static final HSLFSlideShowImpl create() { + InputStream is = HSLFSlideShowImpl.class.getResourceAsStream("/org/apache/poi/hslf/data/empty.ppt"); + if (is == null) { + throw new RuntimeException("Missing resource 'empty.ppt'"); + } + try { + return new HSLFSlideShowImpl(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Extracts the main PowerPoint document stream from the + * POI file, ready to be passed + * + * @throws IOException + */ + private void readPowerPointStream() throws IOException + { + // Get the main document stream + DocumentEntry docProps = + (DocumentEntry)directory.getEntry("PowerPoint Document"); + + // Grab the document stream + _docstream = new byte[docProps.getSize()]; + directory.createDocumentInputStream("PowerPoint Document").read(_docstream); + } + + /** + * Builds the list of records, based on the contents + * of the PowerPoint stream + */ + private void buildRecords() + { + // The format of records in a powerpoint file are: + // + // + // + // If it has a zero length, following it will be another record + // + // If it has a length, depending on its type it may have children or data + // If it has children, these will follow straight away + // > + // If it has data, this will come straigh after, and run for the length + // + // All lengths given exclude the 8 byte record header + // (Data records are known as Atoms) + + // Document should start with: + // 0F 00 E8 03 ## ## ## ## + // (type 1000 = document, info 00 0f is normal, rest is document length) + // 01 00 E9 03 28 00 00 00 + // (type 1001 = document atom, info 00 01 normal, 28 bytes long) + // 80 16 00 00 E0 10 00 00 xx xx xx xx xx xx xx xx + // 05 00 00 00 0A 00 00 00 xx xx xx + // (the contents of the document atom, not sure what it means yet) + // (records then follow) + + // When parsing a document, look to see if you know about that type + // of the current record. If you know it's a type that has children, + // process the record's data area looking for more records + // If you know about the type and it doesn't have children, either do + // something with the data (eg TextRun) or skip over it + // If you don't know about the type, play safe and skip over it (using + // its length to know where the next record will start) + // + + _records = read(_docstream, (int)currentUser.getCurrentEditOffset()); + } + + private Record[] read(byte[] docstream, int usrOffset){ + //sort found records by offset. + //(it is not necessary but SlideShow.findMostRecentCoreRecords() expects them sorted) + NavigableMap records = new TreeMap(); // offset -> record + Map persistIds = new HashMap(); // offset -> persistId + initRecordOffsets(docstream, usrOffset, records, persistIds); + HSLFSlideShowEncrypted decryptData = new HSLFSlideShowEncrypted(docstream, records); + + for (Map.Entry entry : records.entrySet()) { + Integer offset = entry.getKey(); + Record record = entry.getValue(); + Integer persistId = persistIds.get(offset); + if (record == null) { + // all plain records have been already added, + // only new records need to be decrypted (tbd #35897) + decryptData.decryptRecord(docstream, persistId, offset); + record = Record.buildRecordAtOffset(docstream, offset); + entry.setValue(record); + } + + if (record instanceof PersistRecord) { + ((PersistRecord)record).setPersistId(persistId); + } + } + + return records.values().toArray(new Record[records.size()]); + } + + private void initRecordOffsets(byte[] docstream, int usrOffset, NavigableMap recordMap, Map offset2id) { + while (usrOffset != 0){ + UserEditAtom usr = (UserEditAtom) Record.buildRecordAtOffset(docstream, usrOffset); + recordMap.put(usrOffset, usr); + + int psrOffset = usr.getPersistPointersOffset(); + PersistPtrHolder ptr = (PersistPtrHolder)Record.buildRecordAtOffset(docstream, psrOffset); + recordMap.put(psrOffset, ptr); + + for(Map.Entry entry : ptr.getSlideLocationsLookup().entrySet()) { + Integer offset = entry.getValue(); + Integer id = entry.getKey(); + recordMap.put(offset, null); // reserve a slot for the record + offset2id.put(offset, id); + } + + usrOffset = usr.getLastUserEditAtomOffset(); + + // check for corrupted user edit atom and try to repair it + // if the next user edit atom offset is already known, we would go into an endless loop + if (usrOffset > 0 && recordMap.containsKey(usrOffset)) { + // a user edit atom is usually located 36 byte before the smallest known record offset + usrOffset = recordMap.firstKey()-36; + // check that we really are located on a user edit atom + int ver_inst = LittleEndian.getUShort(docstream, usrOffset); + int type = LittleEndian.getUShort(docstream, usrOffset+2); + int len = LittleEndian.getInt(docstream, usrOffset+4); + if (ver_inst == 0 && type == 4085 && (len == 0x1C || len == 0x20)) { + logger.log(POILogger.WARN, "Repairing invalid user edit atom"); + usr.setLastUserEditAtomOffset(usrOffset); + } else { + throw new CorruptPowerPointFileException("Powerpoint document contains invalid user edit atom"); + } + } + } + } + + public DocumentEncryptionAtom getDocumentEncryptionAtom() { + for (Record r : _records) { + if (r instanceof DocumentEncryptionAtom) { + return (DocumentEncryptionAtom)r; + } + } + return null; + } + + + /** + * Find the "Current User" stream, and load it + */ + private void readCurrentUserStream() { + try { + currentUser = new CurrentUserAtom(directory); + } catch(IOException ie) { + logger.log(POILogger.ERROR, "Error finding Current User Atom:\n" + ie); + currentUser = new CurrentUserAtom(); + } + } + + /** + * Find any other streams from the filesystem, and load them + */ + private void readOtherStreams() { + // Currently, there aren't any + } + + /** + * Find and read in pictures contained in this presentation. + * This is lazily called as and when we want to touch pictures. + */ + @SuppressWarnings("unused") + private void readPictures() throws IOException { + _pictures = new ArrayList(); + + // if the presentation doesn't contain pictures - will use a null set instead + if (!directory.hasEntry("Pictures")) return; + + HSLFSlideShowEncrypted decryptData = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); + + DocumentEntry entry = (DocumentEntry)directory.getEntry("Pictures"); + byte[] pictstream = new byte[entry.getSize()]; + DocumentInputStream is = directory.createDocumentInputStream(entry); + is.read(pictstream); + is.close(); + + + int pos = 0; + // An empty picture record (length 0) will take up 8 bytes + while (pos <= (pictstream.length-8)) { + int offset = pos; + + decryptData.decryptPicture(pictstream, offset); + + // Image signature + int signature = LittleEndian.getUShort(pictstream, pos); + pos += LittleEndian.SHORT_SIZE; + // Image type + 0xF018 + int type = LittleEndian.getUShort(pictstream, pos); + pos += LittleEndian.SHORT_SIZE; + // Image size (excluding the 8 byte header) + int imgsize = LittleEndian.getInt(pictstream, pos); + pos += LittleEndian.INT_SIZE; + + // When parsing the BStoreDelay stream, [MS-ODRAW] says that we + // should terminate if the type isn't 0xf007 or 0xf018->0xf117 + if (!((type == 0xf007) || (type >= 0xf018 && type <= 0xf117))) + break; + + // The image size must be 0 or greater + // (0 is allowed, but odd, since we do wind on by the header each + // time, so we won't get stuck) + if(imgsize < 0) { + throw new CorruptPowerPointFileException("The file contains a picture, at position " + _pictures.size() + ", which has a negatively sized data length, so we can't trust any of the picture data"); + } + + // If they type (including the bonus 0xF018) is 0, skip it + if(type == 0) { + logger.log(POILogger.ERROR, "Problem reading picture: Invalid image type 0, on picture with length " + imgsize + ".\nYou document will probably become corrupted if you save it!"); + logger.log(POILogger.ERROR, "" + pos); + } else { + // Build the PictureData object from the data + try { + HSLFPictureData pict = HSLFPictureData.create(type - 0xF018); + + // Copy the data, ready to pass to PictureData + byte[] imgdata = new byte[imgsize]; + System.arraycopy(pictstream, pos, imgdata, 0, imgdata.length); + pict.setRawData(imgdata); + + pict.setOffset(offset); + _pictures.add(pict); + } catch(IllegalArgumentException e) { + logger.log(POILogger.ERROR, "Problem reading picture: " + e + "\nYou document will probably become corrupted if you save it!"); + } + } + + pos += imgsize; + } + } + + /** + * remove duplicated UserEditAtoms and merge PersistPtrHolder, i.e. + * remove document edit history + */ + public void normalizeRecords() { + try { + updateAndWriteDependantRecords(null, null); + } catch (IOException e) { + throw new CorruptPowerPointFileException(e); + } + _records = HSLFSlideShowEncrypted.normalizeRecords(_records); + } + + + /** + * This is a helper functions, which is needed for adding new position dependent records + * or finally write the slideshow to a file. + * + * @param os the stream to write to, if null only the references are updated + * @param interestingRecords a map of interesting records (PersistPtrHolder and UserEditAtom) + * referenced by their RecordType. Only the very last of each type will be saved to the map. + * May be null, if not needed. + * @throws IOException + */ + public void updateAndWriteDependantRecords(OutputStream os, Map interestingRecords) + throws IOException { + // For position dependent records, hold where they were and now are + // As we go along, update, and hand over, to any Position Dependent + // records we happen across + Hashtable oldToNewPositions = new Hashtable(); + + // First pass - figure out where all the position dependent + // records are going to end up, in the new scheme + // (Annoyingly, some powerpoint files have PersistPtrHolders + // that reference slides after the PersistPtrHolder) + UserEditAtom usr = null; + PersistPtrHolder ptr = null; + CountingOS cos = new CountingOS(); + for (Record record : _records) { + // all top level records are position dependent + assert(record instanceof PositionDependentRecord); + PositionDependentRecord pdr = (PositionDependentRecord)record; + int oldPos = pdr.getLastOnDiskOffset(); + int newPos = cos.size(); + pdr.setLastOnDiskOffset(newPos); + if (oldPos != UNSET_OFFSET) { + // new records don't need a mapping, as they aren't in a relation yet + oldToNewPositions.put(oldPos,newPos); + } + + // Grab interesting records as they come past + // this will only save the very last record of each type + RecordTypes.Type saveme = null; + int recordType = (int)record.getRecordType(); + if (recordType == RecordTypes.PersistPtrIncrementalBlock.typeID) { + saveme = RecordTypes.PersistPtrIncrementalBlock; + ptr = (PersistPtrHolder)pdr; + } else if (recordType == RecordTypes.UserEditAtom.typeID) { + saveme = RecordTypes.UserEditAtom; + usr = (UserEditAtom)pdr; + } + if (interestingRecords != null && saveme != null) { + interestingRecords.put(saveme,pdr); + } + + // Dummy write out, so the position winds on properly + record.writeOut(cos); + } + + assert(usr != null && ptr != null); + + Map persistIds = new HashMap(); + for (Map.Entry entry : ptr.getSlideLocationsLookup().entrySet()) { + persistIds.put(oldToNewPositions.get(entry.getValue()), entry.getKey()); + } + + HSLFSlideShowEncrypted encData = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); + + for (Record record : _records) { + assert(record instanceof PositionDependentRecord); + // We've already figured out their new location, and + // told them that + // Tell them of the positions of the other records though + PositionDependentRecord pdr = (PositionDependentRecord)record; + Integer persistId = persistIds.get(pdr.getLastOnDiskOffset()); + if (persistId == null) persistId = 0; + + // For now, we're only handling PositionDependentRecord's that + // happen at the top level. + // In future, we'll need the handle them everywhere, but that's + // a bit trickier + pdr.updateOtherRecordReferences(oldToNewPositions); + + // Whatever happens, write out that record tree + if (os != null) { + record.writeOut(encData.encryptRecord(os, persistId, record)); + } + } + + // Update and write out the Current User atom + int oldLastUserEditAtomPos = (int)currentUser.getCurrentEditOffset(); + Integer newLastUserEditAtomPos = oldToNewPositions.get(oldLastUserEditAtomPos); + if(usr == null || newLastUserEditAtomPos == null || usr.getLastOnDiskOffset() != newLastUserEditAtomPos) { + throw new HSLFException("Couldn't find the new location of the last UserEditAtom that used to be at " + oldLastUserEditAtomPos); + } + currentUser.setCurrentEditOffset(usr.getLastOnDiskOffset()); + } + + /** + * Writes out the slideshow file the is represented by an instance + * of this class. + * It will write out the common OLE2 streams. If you require all + * streams to be written out, pass in preserveNodes + * @param out The OutputStream to write to. + * @throws IOException If there is an unexpected IOException from + * the passed in OutputStream + */ + public void write(OutputStream out) throws IOException { + // Write out, but only the common streams + write(out,false); + } + /** + * Writes out the slideshow file the is represented by an instance + * of this class. + * If you require all streams to be written out (eg Marcos, embeded + * documents), then set preserveNodes to true + * @param out The OutputStream to write to. + * @param preserveNodes Should all OLE2 streams be written back out, or only the common ones? + * @throws IOException If there is an unexpected IOException from + * the passed in OutputStream + */ + public void write(OutputStream out, boolean preserveNodes) throws IOException { + // read properties and pictures, with old encryption settings where appropriate + if(_pictures == null) { + readPictures(); + } + getDocumentSummaryInformation(); + + // set new encryption settings + HSLFSlideShowEncrypted encryptedSS = new HSLFSlideShowEncrypted(getDocumentEncryptionAtom()); + _records = encryptedSS.updateEncryptionRecord(_records); + + // Get a new Filesystem to write into + POIFSFileSystem outFS = new POIFSFileSystem(); + + // The list of entries we've written out + List writtenEntries = new ArrayList(1); + + // Write out the Property Streams + writeProperties(outFS, writtenEntries); + + BufAccessBAOS baos = new BufAccessBAOS(); + + // For position dependent records, hold where they were and now are + // As we go along, update, and hand over, to any Position Dependent + // records we happen across + updateAndWriteDependantRecords(baos, null); + + // Update our cached copy of the bytes that make up the PPT stream + _docstream = new byte[baos.size()]; + System.arraycopy(baos.getBuf(), 0, _docstream, 0, baos.size()); + + // Write the PPT stream into the POIFS layer + ByteArrayInputStream bais = new ByteArrayInputStream(_docstream); + outFS.createDocument(bais,"PowerPoint Document"); + writtenEntries.add("PowerPoint Document"); + + currentUser.setEncrypted(encryptedSS.getDocumentEncryptionAtom() != null); + currentUser.writeToFS(outFS); + writtenEntries.add("Current User"); + + + if (_pictures.size() > 0) { + BufAccessBAOS pict = new BufAccessBAOS(); + for (HSLFPictureData p : _pictures) { + int offset = pict.size(); + p.write(pict); + encryptedSS.encryptPicture(pict.getBuf(), offset); + } + outFS.createDocument( + new ByteArrayInputStream(pict.getBuf(), 0, pict.size()), "Pictures" + ); + writtenEntries.add("Pictures"); + } + + // If requested, write out any other streams we spot + if(preserveNodes) { + EntryUtils.copyNodes(directory.getFileSystem(), outFS, writtenEntries); + } + + // Send the POIFSFileSystem object out to the underlying stream + outFS.writeFilesystem(out); + } + + /** + * For a given named property entry, either return it or null if + * if it wasn't found + * + * @param setName The property to read + * @return The value of the given property or null if it wasn't found. + */ + protected PropertySet getPropertySet(String setName) { + DocumentEncryptionAtom dea = getDocumentEncryptionAtom(); + return (dea == null) + ? super.getPropertySet(setName) + : super.getPropertySet(setName, dea.getEncryptionInfo()); + } + + /** + * Writes out the standard Documment Information Properties (HPSF) + * @param outFS the POIFSFileSystem to write the properties into + * @param writtenEntries a list of POIFS entries to add the property names too + * + * @throws IOException if an error when writing to the + * {@link POIFSFileSystem} occurs + */ + protected void writeProperties(POIFSFileSystem outFS, List writtenEntries) throws IOException { + super.writeProperties(outFS, writtenEntries); + DocumentEncryptionAtom dea = getDocumentEncryptionAtom(); + if (dea != null) { + CryptoAPIEncryptor enc = (CryptoAPIEncryptor)dea.getEncryptionInfo().getEncryptor(); + try { + enc.getDataStream(outFS.getRoot()); // ignore OutputStream + } catch (IOException e) { + throw e; + } catch (GeneralSecurityException e) { + throw new IOException(e); + } + } + } + + /* ******************* adding methods follow ********************* */ + + /** + * Adds a new root level record, at the end, but before the last + * PersistPtrIncrementalBlock. + */ + public synchronized int appendRootLevelRecord(Record newRecord) { + int addedAt = -1; + Record[] r = new Record[_records.length+1]; + boolean added = false; + for(int i=(_records.length-1); i>=0; i--) { + if(added) { + // Just copy over + r[i] = _records[i]; + } else { + r[(i+1)] = _records[i]; + if(_records[i] instanceof PersistPtrHolder) { + r[i] = newRecord; + added = true; + addedAt = i; + } + } + } + _records = r; + return addedAt; + } + + /** + * Add a new picture to this presentation. + * + * @return offset of this picture in the Pictures stream + */ + public int addPicture(HSLFPictureData img) { + // Process any existing pictures if we haven't yet + if(_pictures == null) { + try { + readPictures(); + } catch(IOException e) { + throw new CorruptPowerPointFileException(e.getMessage()); + } + } + + // Add the new picture in + int offset = 0; + if(_pictures.size() > 0) { + HSLFPictureData prev = _pictures.get(_pictures.size() - 1); + offset = prev.getOffset() + prev.getRawData().length + 8; + } + img.setOffset(offset); + _pictures.add(img); + return offset; + } + + /* ******************* fetching methods follow ********************* */ + + + /** + * Returns an array of all the records found in the slideshow + */ + public Record[] getRecords() { return _records; } + + /** + * Returns an array of the bytes of the file. Only correct after a + * call to open or write - at all other times might be wrong! + */ + public byte[] getUnderlyingBytes() { return _docstream; } + + /** + * Fetch the Current User Atom of the document + */ + public CurrentUserAtom getCurrentUserAtom() { return currentUser; } + + /** + * Return array of pictures contained in this presentation + * + * @return array with the read pictures or null if the + * presentation doesn't contain pictures. + */ + public HSLFPictureData[] getPictures() { + if(_pictures == null) { + try { + readPictures(); + } catch(IOException e) { + throw new CorruptPowerPointFileException(e.getMessage()); + } + } + + return _pictures.toArray(new HSLFPictureData[_pictures.size()]); + } + + /** + * Gets embedded object data from the slide show. + * + * @return the embedded objects. + */ + public HSLFObjectData[] getEmbeddedObjects() { + if (_objects == null) { + List objects = new ArrayList(); + for (Record r : _records) { + if (r instanceof ExOleObjStg) { + objects.add(new HSLFObjectData((ExOleObjStg)r)); + } + } + _objects = objects.toArray(new HSLFObjectData[objects.size()]); + } + return _objects; + } + + + private static class BufAccessBAOS extends ByteArrayOutputStream { + public byte[] getBuf() { + return buf; + } + } + + private static class CountingOS extends OutputStream { + int count = 0; + public void write(int b) throws IOException { + count++; + } + + public void write(byte[] b) throws IOException { + count += b.length; + } + + public void write(byte[] b, int off, int len) throws IOException { + count += len; + } + + public int size() { + return count; + } + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextBox.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextBox.java new file mode 100644 index 0000000000..b7895a6ac5 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextBox.java @@ -0,0 +1,92 @@ +/* ==================================================================== + 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.*; +import org.apache.poi.sl.usermodel.*; + +/** + * Represents a TextFrame shape in PowerPoint. + *

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

    + * + * @author Yegor Kozlov + */ +public class HSLFTextBox extends HSLFTextShape { + + /** + * Create a TextBox object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected HSLFTextBox(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + + } + + /** + * Create a new TextBox. This constructor is used when a new shape is created. + * + * @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 HSLFTextBox(ShapeContainer parent){ + super(parent); + } + + /** + * Create a new TextBox. This constructor is used when a new shape is created. + * + */ + public HSLFTextBox(){ + this(null); + } + + /** + * Create a new TextBox and initialize its internal structures + * + * @return the created EscherContainerRecord which holds shape data + */ + protected EscherContainerRecord createSpContainer(boolean isChild){ + _escherContainer = super.createSpContainer(isChild); + + setShapeType(ShapeType.TEXT_BOX); + + //set default properties for a TextBox + setEscherProperty(EscherProperties.FILL__FILLCOLOR, 0x8000004); + setEscherProperty(EscherProperties.FILL__FILLBACKCOLOR, 0x8000000); + setEscherProperty(EscherProperties.FILL__NOFILLHITTEST, 0x100000); + setEscherProperty(EscherProperties.LINESTYLE__COLOR, 0x8000001); + setEscherProperty(EscherProperties.LINESTYLE__NOLINEDRAWDASH, 0x80000); + setEscherProperty(EscherProperties.SHADOWSTYLE__COLOR, 0x8000002); + + // init paragraphs + getTextParagraphs(); + + return _escherContainer; + } + + protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ + setVerticalAlignment(VerticalAlignment.TOP); + setEscherProperty(EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20002); + } + +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java new file mode 100644 index 0000000000..0b90f15a9d --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java @@ -0,0 +1,1089 @@ +/* ==================================================================== + 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 java.awt.Color; +import java.util.*; + +import org.apache.poi.hslf.model.textproperties.*; +import org.apache.poi.hslf.record.*; +import org.apache.poi.sl.usermodel.TextParagraph; +import org.apache.poi.util.*; + +/** + * This class represents a run of text in a powerpoint document. That + * run could be text on a sheet, or text in a note. + * It is only a very basic class for now + * + * @author Nick Burch + */ + +public final class HSLFTextParagraph implements TextParagraph { + protected static POILogger logger = POILogFactory.getLogger(HSLFTextParagraph.class); + + /** + * How to align the text + */ + /* package */ static final int AlignLeft = 0; + /* package */ static final int AlignCenter = 1; + /* package */ static final int AlignRight = 2; + /* package */ static final int AlignJustify = 3; + + + // Note: These fields are protected to help with unit testing + // Other classes shouldn't really go playing with them! + private final TextHeaderAtom _headerAtom; + private final TextBytesAtom _byteAtom; + private final TextCharsAtom _charAtom; + private StyleTextPropAtom _styleAtom; + private TextPropCollection _paragraphStyle = new TextPropCollection(1); + + protected TextRulerAtom _ruler; + protected List _runs = new ArrayList(); + protected HSLFTextShape _parentShape; + private HSLFSheet _sheet; + private int shapeId; + + /** + * all text run records that follow TextHeaderAtom. + * (there can be misc InteractiveInfo, TxInteractiveInfo and other records) + */ + private Record[] _records; + // private StyleTextPropAtom styleTextPropAtom; + private StyleTextProp9Atom styleTextProp9Atom; + + /** + * Constructs a Text Run from a Unicode text block. + * Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided. + * + * @param tha the TextHeaderAtom that defines what's what + * @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided + * @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided + * @param sta the StyleTextPropAtom which defines the character stylings + */ + /* package */ HSLFTextParagraph( + TextHeaderAtom tha, + TextBytesAtom tba, + TextCharsAtom tca, + StyleTextPropAtom sta + ) { + _headerAtom = tha; + _styleAtom = sta; + _byteAtom = tba; + _charAtom = tca; + } + + /* package */ HSLFTextParagraph(HSLFTextParagraph other) { + _headerAtom = other._headerAtom; + _styleAtom = other._styleAtom; + _byteAtom = other._byteAtom; + _charAtom = other._charAtom; + _paragraphStyle = other._paragraphStyle; + _parentShape = other._parentShape; + _sheet = other._sheet; + _ruler = other._ruler; // ???? + shapeId = other.shapeId; + _records = other._records; + } + + public void addTextRun(HSLFTextRun run) { + _runs.add(run); + } + + /** + * Fetch the rich text runs (runs of text with the same styling) that + * are contained within this block of text + */ + public List getTextRuns() { + return _runs; + } + + public TextPropCollection getParagraphStyle() { + return _paragraphStyle; + } + + public void setParagraphStyle(TextPropCollection paragraphStyle) { + _paragraphStyle = paragraphStyle; + } + + /** + * Supply the Sheet we belong to, which might have an assigned SlideShow + * Also passes it on to our child RichTextRuns + */ + public void supplySheet(HSLFSheet sheet){ + this._sheet = sheet; + + if (_runs == null) return; + for(HSLFTextRun rt : _runs) { + rt.updateSheet(); + } + } + + public HSLFSheet getSheet(){ + return this._sheet; + } + + /** + * @return Shape ID + */ + protected int getShapeId(){ + return shapeId; + } + + /** + * @param id Shape ID + */ + protected void setShapeId(int id){ + shapeId = id; + } + + /** + * @return 0-based index of the text run in the SLWT container + */ + protected int getIndex(){ + return (_headerAtom != null) ? _headerAtom.getIndex() : -1; + } + + /** + * Sets the index of the paragraph in the SLWT container + * + * @param index + */ + protected void setIndex(int index) { + if (_headerAtom != null) _headerAtom.setIndex(index); + } + + /** + * Returns the type of the text, from the TextHeaderAtom. + * Possible values can be seen from TextHeaderAtom + * @see org.apache.poi.hslf.record.TextHeaderAtom + */ + public int getRunType() { + return (_headerAtom != null) ? _headerAtom.getTextType() : -1; + } + + /** + * Is this Text Run one from a {@link PPDrawing}, or is it + * one from the {@link SlideListWithText}? + */ + public boolean isDrawingBased() { + return (getIndex() == -1); + } + + public TextRulerAtom getTextRuler(){ + return _ruler; + + } + + public TextRulerAtom createTextRuler(){ + _ruler = getTextRuler(); + if (_ruler == null) { + _ruler = TextRulerAtom.getParagraphInstance(); + _headerAtom.getParentRecord().appendChildRecord(_ruler); + } + return _ruler; + } + + /** + * Returns records that make up this text run + * + * @return text run records + */ + public Record[] getRecords(){ + return _records; + } + + /** Numbered List info */ + public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) { + this.styleTextProp9Atom = styleTextProp9Atom; + } + + /** Numbered List info */ + public StyleTextProp9Atom getStyleTextProp9Atom() { + return this.styleTextProp9Atom; + } + + /** Characters covered */ + public StyleTextPropAtom getStyleTextPropAtom() { + return this._styleAtom; + } + + /** + * Fetch the value of the given Paragraph related TextProp. + * Returns -1 if that TextProp isn't present. + * If the TextProp isn't present, the value from the appropriate + * Master Sheet will apply. + */ + private int getParaTextPropVal(String propName) { + TextProp prop = null; + boolean hardAttribute = false; + if (_paragraphStyle != null){ + prop = _paragraphStyle.findByName(propName); + + BitMaskTextProp maskProp = (BitMaskTextProp)_paragraphStyle.findByName(ParagraphFlagsTextProp.NAME); + hardAttribute = maskProp != null && maskProp.getValue() == 0; + } + if (prop == null && !hardAttribute){ + HSLFSheet sheet = _parentShape.getSheet(); + int txtype = _parentShape.getRunType(); + HSLFMasterSheet master = sheet.getMasterSheet(); + if (master != null) + prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false); + } + + return prop == null ? -1 : prop.getValue(); + } + + /** + * Sets the value of the given Character TextProp, add if required + * @param propName The name of the Character TextProp + * @param val The value to set for the TextProp + */ + public void setParaTextPropVal(String propName, int val) { + // Ensure we have the StyleTextProp atom we're going to need + if(_paragraphStyle == null) { + ensureStyleAtomPresent(); + // paragraphStyle will now be defined + } + + assert(_paragraphStyle!=null); + TextProp tp = fetchOrAddTextProp(_paragraphStyle, propName); + tp.setValue(val); + } + + /** + * Ensure a StyleTextPropAtom is present for this run, + * by adding if required. Normally for internal TextRun use. + */ + protected StyleTextPropAtom ensureStyleAtomPresent() { + if (_styleAtom != null) { + return _styleAtom; + } + + _styleAtom = ensureStyleAtomPresent(_headerAtom, _byteAtom, _charAtom); + _paragraphStyle = _styleAtom.getParagraphStyles().get(0); + + return _styleAtom; + } + + protected static StyleTextPropAtom ensureStyleAtomPresent(TextHeaderAtom header, TextBytesAtom tbytes, TextCharsAtom tchars) { + RecordContainer wrapper = header.getParentRecord(); + StyleTextPropAtom styleAtom = null; + + boolean afterHeader = false; + for (Record record : wrapper.getChildRecords()) { + if (afterHeader && record.getRecordType() == RecordTypes.TextHeaderAtom.typeID) break; + afterHeader |= (header == record); + if (afterHeader && record.getRecordType() == RecordTypes.StyleTextPropAtom.typeID) { + styleAtom = (StyleTextPropAtom)record; + break; + } + } + + if (styleAtom != null) return styleAtom; + + String rawText = (tchars != null) ? tchars.getText() : tbytes.getText(); + + // Create a new one at the right size + styleAtom = new StyleTextPropAtom(rawText.length()+1); + + // Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom + wrapper.addChildAfter(styleAtom, (tbytes == null ? tchars : tbytes)); + + return styleAtom; + } + + @Override + public Iterator iterator() { + return _runs.iterator(); + } + + @Override + public double getLeftMargin() { + int val = getParaTextPropVal("text.offset"); + return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI); + } + + @Override + public void setLeftMargin(double leftMargin) { + int val = (int)(leftMargin*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI); + setParaTextPropVal("text.offset", val); + } + + @Override + public double getRightMargin() { + // TODO: find out, how to determine this value + return 0; + } + + @Override + public void setRightMargin(double rightMargin) { + // TODO: find out, how to set this value + } + + @Override + public double getIndent() { + int val = getParaTextPropVal("bullet.offset"); + return val*HSLFShape.POINT_DPI/((double)HSLFShape.MASTER_DPI); + } + + @Override + public void setIndent(double intent) { + int val = (int)(intent*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI); + setParaTextPropVal("bullet.offset", val); + } + + @Override + public String getDefaultFontFamily() { + return (_runs.isEmpty() ? "Arial" : _runs.get(0).getFontFamily()); + } + + @Override + public double getDefaultFontSize() { + return (_runs.isEmpty() ? 12 : _runs.get(0).getFontSize()); + } + + /** + * Sets the type of horizontal alignment for the paragraph. + * + * @param align - the type of alignment + */ + public void setAlignment(org.apache.poi.sl.usermodel.TextParagraph.TextAlign align) { + int alignInt; + switch (align) { + default: + case LEFT: alignInt = AlignmentTextProp.LEFT; break; + case CENTER: alignInt = AlignmentTextProp.CENTER; break; + case RIGHT: alignInt = AlignmentTextProp.RIGHT; break; + case DIST: // TODO: DIST doesn't not exist within hslf, check mapping + case JUSTIFY: alignInt = AlignmentTextProp.JUSTIFY; break; + case JUSTIFY_LOW: alignInt = AlignmentTextProp.JUSTIFYLOW; break; + case THAI_DIST: alignInt = AlignmentTextProp.THAIDISTRIBUTED; break; + } + setParaTextPropVal("alignment", alignInt); + } + + @Override + public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() { + switch (getParaTextPropVal("alignment")) { + default: + case AlignmentTextProp.LEFT: return TextAlign.LEFT; + case AlignmentTextProp.CENTER: return TextAlign.CENTER; + case AlignmentTextProp.RIGHT: return TextAlign.RIGHT; + case AlignmentTextProp.JUSTIFY: return TextAlign.JUSTIFY; + case AlignmentTextProp.JUSTIFYLOW: return TextAlign.JUSTIFY_LOW; + case AlignmentTextProp.THAIDISTRIBUTED: return TextAlign.THAI_DIST; + } + } + + public org.apache.poi.sl.usermodel.TextParagraph.FontAlign getFontAlign() { + // TODO Auto-generated method stub + return null; + } + + public org.apache.poi.sl.usermodel.TextParagraph.BulletStyle getBulletStyle() { + // TODO Auto-generated method stub + return null; + } + + @Override + public HSLFTextShape getParentShape() { + return _parentShape; + } + + public void setParentShape(HSLFTextShape parentShape) { + _parentShape = parentShape; + } + + + /** + * + * @return indentation level + */ + public int getIndentLevel() { + return _paragraphStyle == null ? 0 : _paragraphStyle.getReservedField(); + } + + /** + * Sets indentation level + * + * @param level indentation level. Must be in the range [0, 4] + */ + public void setIndentLevel(int level) { + if( _paragraphStyle != null ) _paragraphStyle.setReservedField((short)level); + } + + /** + * Sets whether this rich text run has bullets + */ + public void setBullet(boolean flag) { + setFlag(ParagraphFlagsTextProp.BULLET_IDX, flag); + } + + /** + * Returns whether this rich text run has bullets + */ + public boolean isBullet() { + return getFlag(ParagraphFlagsTextProp.BULLET_IDX); + } + + /** + * Returns whether this rich text run has bullets + */ + public boolean isBulletHard() { + return getFlag(ParagraphFlagsTextProp.BULLET_IDX); + } + + /** + * Sets the bullet character + */ + public void setBulletChar(char c) { + setParaTextPropVal("bullet.char", c); + } + + /** + * Returns the bullet character + */ + public char getBulletChar() { + return (char)getParaTextPropVal("bullet.char"); + } + + /** + * Sets the bullet size + */ + public void setBulletSize(int size) { + setParaTextPropVal("bullet.size", size); + } + + /** + * Returns the bullet size + */ + public int getBulletSize() { + return getParaTextPropVal("bullet.size"); + } + + /** + * Sets the bullet color + */ + public void setBulletColor(Color color) { + int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB(); + setParaTextPropVal("bullet.color", rgb); + } + + /** + * Returns the bullet color + */ + public Color getBulletColor() { + int rgb = getParaTextPropVal("bullet.color"); + if (rgb == -1) { + // if bullet color is undefined, return color of first run + if (_runs.isEmpty()) return null; + return _runs.get(0).getFontColor(); + } + + int cidx = rgb >> 24; + if (rgb % 0x1000000 == 0){ + if (_sheet == null) return null; + ColorSchemeAtom ca = _sheet.getColorScheme(); + if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx); + } + Color tmp = new Color(rgb, true); + return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); + } + + /** + * Sets the bullet font + */ + public void setBulletFont(int idx) { + setParaTextPropVal("bullet.font", idx); + setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true); + } + + /** + * Returns the bullet font + */ + public int getBulletFont() { + return getParaTextPropVal("bullet.font"); + } + + /** + * Sets the line spacing. + *

    + * If linespacing >= 0, then linespacing is a percentage of normal line height. + * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates. + *

    + */ + public void setLineSpacing(int val) { + setParaTextPropVal("linespacing", val); + } + + /** + * Returns the line spacing + *

    + * If linespacing >= 0, then linespacing is a percentage of normal line height. + * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates. + *

    + * + * @return the spacing between lines + */ + @Override + public double getLineSpacing() { + int val = getParaTextPropVal("linespacing"); + return val == -1 ? 0 : val; + } + + /** + * Sets spacing before a paragraph. + *

    + * If spacebefore >= 0, then spacebefore is a percentage of normal line height. + * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates. + *

    + */ + public void setSpaceBefore(int val) { + setParaTextPropVal("spacebefore", val); + } + + /** + * Returns spacing before a paragraph + *

    + * If spacebefore >= 0, then spacebefore is a percentage of normal line height. + * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates. + *

    + * + * @return the spacing before a paragraph + */ + @Override + public double getSpaceBefore() { + int val = getParaTextPropVal("spacebefore"); + return val == -1 ? 0 : val; + } + + /** + * Sets spacing after a paragraph. + *

    + * If spaceafter >= 0, then spaceafter is a percentage of normal line height. + * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates. + *

    + */ + public void setSpaceAfter(int val) { + setParaTextPropVal("spaceafter", val); + } + + /** + * Returns spacing after a paragraph + *

    + * If spaceafter >= 0, then spaceafter is a percentage of normal line height. + * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates. + *

    + * + * @return the spacing before a paragraph + */ + @Override + public double getSpaceAfter() { + int val = getParaTextPropVal("spaceafter"); + return val == -1 ? 0 : val; + } + + /** + * Returns the named TextProp, either by fetching it (if it exists) or adding it + * (if it didn't) + * @param textPropCol The TextPropCollection to fetch from / add into + * @param textPropName The name of the TextProp to fetch/add + */ + protected static TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) { + // Fetch / Add the TextProp + TextProp tp = textPropCol.findByName(textPropName); + if (tp == null) { + tp = textPropCol.addWithName(textPropName); + } + return tp; + } + + protected boolean getFlag(int index) { + if (_paragraphStyle == null) return false; + + BitMaskTextProp prop = (BitMaskTextProp) _paragraphStyle.findByName(ParagraphFlagsTextProp.NAME); + + if (prop == null) { + if (_sheet != null) { + int txtype = getParentShape().getRunType(); + HSLFMasterSheet master = _sheet.getMasterSheet(); + if (master != null) { + prop = (BitMaskTextProp) master.getStyleAttribute(txtype, getIndentLevel(), ParagraphFlagsTextProp.NAME, false); + } + } else { + logger.log(POILogger.WARN, "MasterSheet is not available"); + } + } + + return prop == null ? false : prop.getSubValue(index); + } + + protected void setFlag(int index, boolean value) { + // Ensure we have the StyleTextProp atom we're going to need + if(_paragraphStyle == null) { + _paragraphStyle = new TextPropCollection(1); + } + + BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(_paragraphStyle, ParagraphFlagsTextProp.NAME); + prop.setSubValue(value,index); + } + + /** + * Saves the modified paragraphs/textrun to the records. + * Also updates the styles to the correct text length. + */ + protected static void storeText(List paragraphs) { + String rawText = toInternalString(getRawText(paragraphs)); + + // Will it fit in a 8 bit atom? + boolean isUnicode = StringUtil.hasMultibyte(rawText); + + TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom; + TextBytesAtom byteAtom = paragraphs.get(0)._byteAtom; + TextCharsAtom charAtom = paragraphs.get(0)._charAtom; + + // Store in the appropriate record + Record oldRecord = null, newRecord = null; + if (isUnicode) { + if (byteAtom != null) { + oldRecord = byteAtom; + newRecord = charAtom = new TextCharsAtom(); + } + charAtom.setText(rawText); + } else { + if (charAtom != null) { + oldRecord = charAtom; + newRecord = byteAtom = new TextBytesAtom(); + } + byte[] byteText = new byte[rawText.length()]; + StringUtil.putCompressedUnicode(rawText,byteText,0); + byteAtom.setText(byteText); + } + + RecordContainer _txtbox = headerAtom.getParentRecord(); + + if (oldRecord != null) { + // swap not appropriated records + Record[] cr = _txtbox.getChildRecords(); + int idx=0; + for (Record r : cr) { + if(r.equals(oldRecord)) break; + idx++; + } + if (idx >= cr.length) { + throw new RuntimeException("child record not found - malformed container record"); + } + cr[idx] = newRecord; + } + + // Ensure a StyleTextPropAtom is present, adding if required + StyleTextPropAtom styleAtom = ensureStyleAtomPresent(headerAtom, byteAtom, charAtom); + + // Update the text length for its Paragraph and Character stylings + // If it's shared: + // * calculate the new length based on the run's old text + // * this should leave in any +1's for the end of block if needed + // If it isn't shared: + // * reset the length, to the new string's length + // * add on +1 if the last block + // The last run needs its stylings to be 1 longer than the raw + // text is. This is to define the stylings that any new text + // that is added will inherit + + styleAtom.clearStyles(); + + TextPropCollection lastPTPC = null, lastRTPC = null; + for (HSLFTextParagraph para : paragraphs) { + TextPropCollection ptpc = para.getParagraphStyle(); + ptpc.updateTextSize(0); + if (!ptpc.equals(lastPTPC)) { + lastPTPC = styleAtom.addParagraphTextPropCollection(0); + lastPTPC.copy(ptpc); + } + for (HSLFTextRun tr : para.getTextRuns()) { + TextPropCollection rtpc = tr.getCharacterStyle(); + if (!rtpc.equals(lastRTPC)) { + lastRTPC = styleAtom.addCharacterTextPropCollection(0); + lastRTPC.copy(rtpc); + } + int len = tr.getLength(); + ptpc.updateTextSize(ptpc.getCharactersCovered()+len); + rtpc.updateTextSize(len); + lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+len); + lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+len); + } + } + + assert(lastPTPC != null && lastRTPC != null); + lastPTPC.updateTextSize(lastPTPC.getCharactersCovered()+1); + lastRTPC.updateTextSize(lastRTPC.getCharactersCovered()+1); + + /** + * If TextSpecInfoAtom is present, we must update the text size in it, + * otherwise the ppt will be corrupted + */ + TextSpecInfoAtom specAtom = (TextSpecInfoAtom)_txtbox.findFirstOfType(RecordTypes.TextSpecInfoAtom.typeID); + int len = rawText.length() + 1; + if(specAtom != null && len != specAtom.getCharactersCovered()) { + specAtom.reset(len); + } + } + + /** + * Adds the supplied text onto the end of the TextParagraphs, + * creating a new RichTextRun for it to sit in. + * + * @param text the text string used by this object. + */ + protected static void appendText(List paragraphs, String text, boolean newParagraph) { + text = toInternalString(text); + + // init paragraphs + assert(!paragraphs.isEmpty()); + + HSLFTextParagraph lastHTP = paragraphs.get(paragraphs.size()-1); + HSLFTextRun lastHTR = lastHTP.getTextRuns().get(lastHTP.getTextRuns().size()-1); + HSLFTextParagraph htp = (newParagraph) ? new HSLFTextParagraph(lastHTP) : lastHTP; + HSLFTextRun htr = new HSLFTextRun(htp); + htr.setText(text); + htr.getCharacterStyle().copy(lastHTR.getCharacterStyle()); + htp.addTextRun(htr); + } + + /** + * Sets (overwrites) the current text. + * Uses the properties of the first paragraph / textrun + * + * @param text the text string used by this object. + */ + public static void setText(List paragraphs, String text) { + text = HSLFTextParagraph.toInternalString(text); + + // init paragraphs + assert(!paragraphs.isEmpty()); + + Iterator paraIter = paragraphs.iterator(); + HSLFTextParagraph firstHTP = paraIter.next(); // keep first + assert(firstHTP != null); + while (paraIter.hasNext()) { + paraIter.next(); + paraIter.remove(); + } + + Iterator runIter = firstHTP.getTextRuns().iterator(); + HSLFTextRun firstHTR = runIter.next(); + assert(firstHTR != null); + while (runIter.hasNext()) { + runIter.next(); + runIter.remove(); + } + + firstHTR.setText(text); + } + + public static String getRawText(List paragraphs) { + StringBuilder sb = new StringBuilder(); + for (HSLFTextParagraph p : paragraphs) { + for (HSLFTextRun r : p.getTextRuns()) { + sb.append(r.getRawText()); + } + sb.append("\r"); + } + sb.deleteCharAt(sb.length()-1); // remove last line break + return sb.toString(); + } + + /** + * Returns a new string with line breaks converted into internal ppt + * representation + */ + protected static String toInternalString(String s) { + String ns = s.replaceAll("\\r?\\n", "\r"); + return ns; + } + + /** + * Converts raw text from the text paragraphs to a formatted string, + * i.e. it converts certain control characters used in the raw txt + * + * @param rawText the raw text + * @param runType the run type of the shape, paragraph or headerAtom. + * use -1 if unknown + * @return the formatted string + */ + public static String toExternalString(String rawText, int runType) { + // PowerPoint seems to store files with \r as the line break + // The messes things up on everything but a Mac, so translate + // them to \n + String text = rawText.replace('\r', '\n'); + + switch (runType) { + // 0xB acts like cariage return in page titles and like blank in the + // others + case -1: + case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE: + case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE: + text = text.replace((char) 0x0B, '\n'); + break; + default: + text = text.replace((char) 0x0B, ' '); + break; + } + + return text; + } + + /** + * For a given PPDrawing, grab all the TextRuns + */ + public static List> findTextParagraphs(PPDrawing ppdrawing) { + List> runsV = new ArrayList>(); + for (EscherTextboxWrapper wrapper : ppdrawing.getTextboxWrappers()) { + // propagate parents to parent-aware records + RecordContainer.handleParentAwareRecords(wrapper); + int shapeId = wrapper.getShapeId(); + List> rv = findTextParagraphs(wrapper); + for (List htpList : rv) { + for (HSLFTextParagraph htp : htpList) { + htp.setShapeId(shapeId); + } + } + runsV.addAll(rv); + } + return runsV; + } + /** + * Scans through the supplied record array, looking for + * a TextHeaderAtom followed by one of a TextBytesAtom or + * a TextCharsAtom. Builds up TextRuns from these + * + * @param records the records to build from + * @param found vector to add any found to + */ + protected static List> findTextParagraphs(final Record[] records) { + return findTextParagraphs(records, null); + } + /** + * Scans through the supplied record array, looking for + * a TextHeaderAtom followed by one of a TextBytesAtom or + * a TextCharsAtom. Builds up TextRuns from these + * + * @param wrapper an EscherTextboxWrapper + */ + protected static List> findTextParagraphs(final EscherTextboxWrapper wrapper) { + return findTextParagraphs(wrapper.getChildRecords(), wrapper.getStyleTextProp9Atom()); + } + + /** + * Scans through the supplied record array, looking for + * a TextHeaderAtom followed by one of a TextBytesAtom or + * a TextCharsAtom. Builds up TextRuns from these + * + * @param records the records to build from + * @param styleTextProp9Atom an optional StyleTextProp9Atom with numbered lists info + */ + protected static List> findTextParagraphs(Record[] records, StyleTextProp9Atom styleTextProp9Atom) { + List> paragraphCollection = new ArrayList>(); + + if (records == null) { + throw new NullPointerException("records need to be filled."); + } + + int recordIdx; + for (recordIdx = 0; recordIdx < records.length; recordIdx++) { + if (records[recordIdx] instanceof TextHeaderAtom) break; + } + + if (recordIdx == records.length) { + logger.log(POILogger.INFO, "No text records found."); + return paragraphCollection; + } + + for (int slwtIndex = 0; recordIdx < records.length-2; slwtIndex++) { + List paragraphs = new ArrayList(); + paragraphCollection.add(paragraphs); + + TextHeaderAtom header = (TextHeaderAtom)records[recordIdx++]; + TextBytesAtom tbytes = null; + TextCharsAtom tchars = null; + StyleTextPropAtom styles = null; + TextRulerAtom ruler = null; + MasterTextPropAtom indents = null; + + List otherRecordList = new ArrayList(); + + for (; recordIdx < records.length; recordIdx++) { + Record r = records[recordIdx]; + long rt = r.getRecordType(); + if (RecordTypes.TextHeaderAtom.typeID == rt) break; + else if (RecordTypes.TextBytesAtom.typeID == rt) tbytes = (TextBytesAtom)r; + else if (RecordTypes.TextCharsAtom.typeID == rt) tchars = (TextCharsAtom)r; + else if (RecordTypes.StyleTextPropAtom.typeID == rt) styles = (StyleTextPropAtom)r; + else if (RecordTypes.TextRulerAtom.typeID == rt) ruler = (TextRulerAtom)r; + else if (RecordTypes.MasterTextPropAtom.typeID == rt) { + indents = (MasterTextPropAtom)r; + otherRecordList.add(indents); + } else { + otherRecordList.add(r); + } + } + + assert(header != null); + if (header.getIndex() == -1) { + header.setIndex(slwtIndex); + } + + Record otherRecords[] = otherRecordList.toArray(new Record[otherRecordList.size()]); + + if (tbytes == null && tchars == null) { + tbytes = new TextBytesAtom(); + logger.log(POILogger.INFO, "bytes nor chars atom doesn't exist. Creating dummy record for later saving."); + } + + String rawText = (tchars != null) ? tchars.getText() : tbytes.getText(); + + for (String para : rawText.split("\r")) { + HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, styles); + paragraphs.add(tpara); + tpara.setStyleTextProp9Atom(styleTextProp9Atom); + tpara._ruler = ruler; + tpara._records = otherRecords; + tpara.getParagraphStyle().updateTextSize(para.length()); + + HSLFTextRun trun = new HSLFTextRun(tpara); + tpara.addTextRun(trun); + trun.setText(para); + } + + if (styles == null) { + styles = ensureStyleAtomPresent(header, tbytes, tchars); + } else { + styles.setParentTextSize(rawText.length()); + } + + applyCharacterStyles(paragraphs, styles.getCharacterStyles()); + applyParagraphStyles(paragraphs, styles.getParagraphStyles()); + if (indents != null) { + applyParagraphIndents(paragraphs, indents.getIndents()); + } + } + + return paragraphCollection; + } + + protected static void applyCharacterStyles(List paragraphs, List charStyles) { + int paraIdx = 0, runIdx = 0; + for (TextPropCollection p : charStyles) { + for (int ccRun = 0, ccStyle = p.getCharactersCovered(); ccRun < ccStyle; ) { + HSLFTextParagraph para = paragraphs.get(paraIdx); + List runs = para.getTextRuns(); + HSLFTextRun trun = runs.get(runIdx); + int len = trun.getLength(); + + if (runIdx+1 >= runs.size()) { + // need to add +1 to the last run of the paragraph + len++; + } + + TextPropCollection pCopy = new TextPropCollection(1); + pCopy.copy(p); + if (ccRun+len <= ccStyle) { + trun.setCharacterStyle(pCopy); + pCopy.updateTextSize(len); + ccRun += len; + } else { + String text = trun.getRawText(); + trun.setText(text.substring(0,ccStyle-ccRun)); + pCopy.updateTextSize(ccStyle-ccRun); + trun.setCharacterStyle(pCopy); + + HSLFTextRun nextRun = new HSLFTextRun(para); + nextRun.setText(text.substring(ccStyle-ccRun)); + runs.add(runIdx+1, nextRun); + + ccRun += ccStyle-ccRun; + } + + // need to compare it again, in case a run has been added afer + if (++runIdx >= runs.size()) { + paraIdx++; + runIdx = 0; + } + } + } + } + + protected static void applyParagraphStyles(List paragraphs, List paraStyles) { + int paraIdx = 0; + for (TextPropCollection p : paraStyles) { + for (int ccPara = 0, ccStyle = p.getCharactersCovered(); ccPara < ccStyle; paraIdx++) { + HSLFTextParagraph para = paragraphs.get(paraIdx); + TextPropCollection pCopy = new TextPropCollection(1); + pCopy.copy(p); + int len = 0; + for (HSLFTextRun trun : para.getTextRuns()) { + len += trun.getLength(); + } + pCopy.updateTextSize(len+1); + para.setParagraphStyle(pCopy); + ccPara += len+1; + } + } + } + + protected static void applyParagraphIndents(List paragraphs, List paraStyles) { + int paraIdx = 0; + for (IndentProp p : paraStyles) { + for (int ccPara = 0, ccStyle = p.getCharactersCovered(); ccPara < ccStyle; paraIdx++) { + HSLFTextParagraph para = paragraphs.get(paraIdx); + int len = 0; + for (HSLFTextRun trun : para.getTextRuns()) { + len += trun.getLength(); + } + para.setIndentLevel(p.getIndentLevel()); + ccPara += len+1; + } + } + } + + protected static List createEmptyParagraph() { + EscherTextboxWrapper wrapper = new EscherTextboxWrapper(); + + TextHeaderAtom tha = new TextHeaderAtom(); + tha.setParentRecord(wrapper); + wrapper.appendChildRecord(tha); + + TextCharsAtom tca = new TextCharsAtom(); + wrapper.appendChildRecord(tca); + + StyleTextPropAtom sta = new StyleTextPropAtom(0); + wrapper.appendChildRecord(sta); + + HSLFTextParagraph htp = new HSLFTextParagraph(tha, null, tca, sta); + htp._records = new Record[0]; + HSLFTextRun htr = new HSLFTextRun(htp); + htp.addTextRun(htr); + + return Arrays.asList(htp); + } + + public EscherTextboxWrapper getTextboxWrapper() { + return (EscherTextboxWrapper)_headerAtom.getParentRecord(); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java index 06980e9ff5..9a10a9b125 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java @@ -17,14 +17,11 @@ package org.apache.poi.hslf.usermodel; +import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.fetchOrAddTextProp; + import java.awt.Color; -import org.apache.poi.hslf.model.*; -import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; -import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.model.textproperties.*; import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.sl.usermodel.TextRun; import org.apache.poi.util.POILogFactory; @@ -40,70 +37,31 @@ public final class HSLFTextRun implements TextRun { /** The TextRun we belong to */ private HSLFTextParagraph parentParagraph; - /** The SlideShow we belong to */ - // private SlideShow slideShow; - - /** Where in the parent TextRun we start from */ - private int startPos; - - /** How long a string (in the parent TextRun) we represent */ - private int length; - + private String _runText = "\r"; private String _fontname; + /** * Our paragraph and character style. * Note - we may share these styles with other RichTextRuns */ - private TextPropCollection paragraphStyle; - private TextPropCollection characterStyle; - private boolean sharingParagraphStyle; - private boolean sharingCharacterStyle; + private TextPropCollection characterStyle = new TextPropCollection(1); /** - * Create a new wrapper around a (currently not) - * rich text string - * @param parent - * @param startAt - * @param len + * Create a new wrapper around a rich text string + * @param parent The parent paragraph */ - public HSLFTextRun(HSLFTextParagraph parent, int startAt, int len) { - this(parent, startAt, len, null, null, false, false); + public HSLFTextRun(HSLFTextParagraph parentParagraph) { + this.parentParagraph = parentParagraph; } - /** - * Create a new wrapper around a rich text string - * @param parent The parent TextRun - * @param startAt The start position of this run - * @param len The length of this run - * @param pStyle The paragraph style property collection - * @param cStyle The character style property collection - * @param pShared The paragraph styles are shared with other runs - * @param cShared The character styles are shared with other runs - */ - public HSLFTextRun(HSLFTextParagraph parent, int startAt, int len, - TextPropCollection pStyle, TextPropCollection cStyle, - boolean pShared, boolean cShared) { - parentParagraph = parent; - startPos = startAt; - length = len; - paragraphStyle = pStyle; - characterStyle = cStyle; - sharingParagraphStyle = pShared; - sharingCharacterStyle = cShared; - } - - /** - * Supply (normally default) textprops, and if they're shared, - * when a run gets them - */ - public void supplyTextProps(TextPropCollection pStyle, TextPropCollection cStyle, boolean pShared, boolean cShared) { - if(paragraphStyle != null || characterStyle != null) { - throw new IllegalStateException("Can't call supplyTextProps if run already has some"); - } - paragraphStyle = pStyle; - characterStyle = cStyle; - sharingParagraphStyle = pShared; - sharingCharacterStyle = cShared; + + public TextPropCollection getCharacterStyle() { + return characterStyle; + } + + public void setCharacterStyle(TextPropCollection characterStyle) { + this.characterStyle = characterStyle; } + /** * Supply the SlideShow we belong to */ @@ -118,65 +76,23 @@ public final class HSLFTextRun implements TextRun { * Get the length of the text */ public int getLength() { - return length; + return _runText.length(); } - /** - * The beginning index, inclusive. - * - * @return the beginning index, inclusive. - */ - public int getStartIndex(){ - return startPos; - } - - /** - * The ending index, exclusive. - * - * @return the ending index, exclusive. - */ - public int getEndIndex(){ - return startPos + length; - } - - /** - * Fetch the text, in output suitable form - */ - public String getText() { - return parentParagraph.getText().substring(startPos, startPos+length); - } /** * Fetch the text, in raw storage form */ public String getRawText() { - return parentParagraph.getRawText().substring(startPos, startPos+length); + return _runText; } /** * Change the text */ public void setText(String text) { - String s = parentParagraph.normalize(text); - setRawText(s); + _runText = text; } - /** - * Change the text - */ - public void setRawText(String text) { - length = text.length(); - parentParagraph.changeTextInRichTextRun(this,text); - } - - /** - * Tells the RichTextRun its new position in the parent TextRun - * @param startAt - */ - public void updateStartPosition(int startAt) { - startPos = startAt; - } - - // --------------- Internal helpers on rich text properties ------- /** @@ -185,31 +101,21 @@ public final class HSLFTextRun implements TextRun { * text property won't be set if there's no CharFlagsTextProp. */ private boolean isCharFlagsTextPropVal(int index) { - return getFlag(true, index); - } - - private boolean getFlag(boolean isCharacter, int index) { - TextPropCollection props; - String propname; - if (isCharacter){ - props = characterStyle; - propname = CharFlagsTextProp.NAME; - } else { - props = paragraphStyle; - propname = ParagraphFlagsTextProp.NAME; - } + return getFlag(index); + } + + protected boolean getFlag(int index) { + if (characterStyle == null) return false; + + BitMaskTextProp prop = (BitMaskTextProp)characterStyle.findByName(CharFlagsTextProp.NAME); - BitMaskTextProp prop = null; - if (props != null){ - prop = (BitMaskTextProp)props.findByName(propname); - } if (prop == null){ HSLFSheet sheet = parentParagraph.getSheet(); if(sheet != null){ - int txtype = parentParagraph.getRunType(); + int txtype = parentParagraph.getParentShape().getRunType(); HSLFMasterSheet master = sheet.getMasterSheet(); if (master != null){ - prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter); + prop = (BitMaskTextProp)master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), CharFlagsTextProp.NAME, true); } } else { logger.log(POILogger.WARN, "MasterSheet is not available"); @@ -224,43 +130,7 @@ public final class HSLFTextRun implements TextRun { * it if required. */ private void setCharFlagsTextPropVal(int index, boolean value) { - if(getFlag(true, index) != value) setFlag(true, index, value); - } - - public void setFlag(boolean isCharacter, int index, boolean value) { - TextPropCollection props; - String propname; - if (isCharacter){ - props = characterStyle; - propname = CharFlagsTextProp.NAME; - } else { - props = paragraphStyle; - propname = ParagraphFlagsTextProp.NAME; - } - - // Ensure we have the StyleTextProp atom we're going to need - if(props == null) { - parentParagraph.ensureStyleAtomPresent(); - props = isCharacter ? characterStyle : paragraphStyle; - } - - BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(props, propname); - prop.setSubValue(value,index); - } - - /** - * Returns the named TextProp, either by fetching it (if it exists) or adding it - * (if it didn't) - * @param textPropCol The TextPropCollection to fetch from / add into - * @param textPropName The name of the TextProp to fetch/add - */ - private TextProp fetchOrAddTextProp(TextPropCollection textPropCol, String textPropName) { - // Fetch / Add the TextProp - TextProp tp = textPropCol.findByName(textPropName); - if(tp == null) { - tp = textPropCol.addWithName(textPropName); - } - return tp; + if(getFlag(index) != value) setFlag(index, value); } /** @@ -277,55 +147,14 @@ public final class HSLFTextRun implements TextRun { if (prop == null){ HSLFSheet sheet = parentParagraph.getSheet(); - int txtype = parentParagraph.getRunType(); + int txtype = parentParagraph.getParentShape().getRunType(); HSLFMasterSheet master = sheet.getMasterSheet(); if (master != null) - prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, true); + prop = master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), propName, true); } return prop == null ? -1 : prop.getValue(); } - /** - * Fetch the value of the given Paragraph related TextProp. - * Returns -1 if that TextProp isn't present. - * If the TextProp isn't present, the value from the appropriate - * Master Sheet will apply. - */ - private int getParaTextPropVal(String propName) { - TextProp prop = null; - boolean hardAttribute = false; - if (paragraphStyle != null){ - prop = paragraphStyle.findByName(propName); - - BitMaskTextProp maskProp = (BitMaskTextProp)paragraphStyle.findByName(ParagraphFlagsTextProp.NAME); - hardAttribute = maskProp != null && maskProp.getValue() == 0; - } - if (prop == null && !hardAttribute){ - HSLFSheet sheet = parentParagraph.getSheet(); - int txtype = parentParagraph.getRunType(); - HSLFMasterSheet master = sheet.getMasterSheet(); - if (master != null) - prop = master.getStyleAttribute(txtype, getIndentLevel(), propName, false); - } - - return prop == null ? -1 : prop.getValue(); - } - - /** - * Sets the value of the given Character TextProp, add if required - * @param propName The name of the Character TextProp - * @param val The value to set for the TextProp - */ - public void setParaTextPropVal(String propName, int val) { - // Ensure we have the StyleTextProp atom we're going to need - if(paragraphStyle == null) { - parentParagraph.ensureStyleAtomPresent(); - // paragraphStyle will now be defined - } - - assert(paragraphStyle!=null); - TextProp tp = fetchOrAddTextProp(paragraphStyle, propName); - tp.setValue(val); - } + /** * Sets the value of the given Paragraph TextProp, add if required * @param propName The name of the Paragraph TextProp @@ -334,11 +163,10 @@ public final class HSLFTextRun implements TextRun { public void setCharTextPropVal(String propName, int val) { // Ensure we have the StyleTextProp atom we're going to need if(characterStyle == null) { - parentParagraph.ensureStyleAtomPresent(); + characterStyle = new TextPropCollection(1); // characterStyle will now be defined } - assert(characterStyle!=null); TextProp tp = fetchOrAddTextProp(characterStyle, propName); tp.setValue(val); } @@ -377,14 +205,14 @@ public final class HSLFTextRun implements TextRun { /** * Is the text underlined? */ - public boolean isUnderline() { + public boolean isUnderlined() { return isCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX); } /** * Is the text underlined? */ - public void setUnderline(boolean underlined) { + public void setUnderlined(boolean underlined) { setCharFlagsTextPropVal(CharFlagsTextProp.UNDERLINE_IDX, underlined); } @@ -452,7 +280,7 @@ public final class HSLFTextRun implements TextRun { /** * Gets the font size */ - public int getFontSize() { + public double getFontSize() { return getCharTextPropVal("font.size"); } @@ -484,7 +312,7 @@ public final class HSLFTextRun implements TextRun { */ public void setFontName(String fontName) { HSLFSheet sheet = parentParagraph.getSheet(); - HSLFSlideShowImpl slideShow = (sheet == null) ? null : sheet.getSlideShow(); + HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow(); if (sheet == null || slideShow == null) { //we can't set font since slideshow is not assigned yet _fontname = fontName; @@ -498,9 +326,10 @@ public final class HSLFTextRun implements TextRun { /** * Gets the font name */ - public String getFontName() { + @Override + public String getFontFamily() { HSLFSheet sheet = parentParagraph.getSheet(); - HSLFSlideShowImpl slideShow = (sheet == null) ? null : sheet.getSlideShow(); + HSLFSlideShow slideShow = (sheet == null) ? null : sheet.getSlideShow(); if (sheet == null || slideShow == null) { return _fontname; } @@ -544,250 +373,29 @@ public final class HSLFTextRun implements TextRun { setFontColor(rgb); } - /** - * Sets the type of horizontal alignment for the text. - * One of the Align* constants defined in the TextBox class. - * - * @param align - the type of alignment - */ - public void setAlignment(int align) { - setParaTextPropVal("alignment", align); - } - /** - * Returns the type of horizontal alignment for the text. - * One of the Align* constants defined in the TextBox class. - * - * @return the type of alignment - */ - public int getAlignment() { - return getParaTextPropVal("alignment"); - } + protected void setFlag(int index, boolean value) { + // Ensure we have the StyleTextProp atom we're going to need + if (characterStyle == null) { + characterStyle = new TextPropCollection(1); + } - /** - * - * @return indentation level - */ - public int getIndentLevel() { - return paragraphStyle == null ? 0 : paragraphStyle.getReservedField(); - } + BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(characterStyle, CharFlagsTextProp.NAME); + prop.setSubValue(value, index); + } - /** - * Sets indentation level - * - * @param level indentation level. Must be in the range [0, 4] - */ - public void setIndentLevel(int level) { - if(paragraphStyle != null ) paragraphStyle.setReservedField((short)level); - } + public TextCap getTextCap() { + return TextCap.NONE; + } - /** - * Sets whether this rich text run has bullets - */ - public void setBullet(boolean flag) { - setFlag(false, ParagraphFlagsTextProp.BULLET_IDX, flag); - } + public boolean isSubscript() { + return false; + } - /** - * Returns whether this rich text run has bullets - */ - public boolean isBullet() { - return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX); - } + public boolean isSuperscript() { + return false; + } - /** - * Returns whether this rich text run has bullets - */ - public boolean isBulletHard() { - return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX); - } - - /** - * Sets the bullet character - */ - public void setBulletChar(char c) { - setParaTextPropVal("bullet.char", c); - } - - /** - * Returns the bullet character - */ - public char getBulletChar() { - return (char)getParaTextPropVal("bullet.char"); - } - - /** - * Sets the bullet offset - */ - public void setBulletOffset(int offset) { - setParaTextPropVal("bullet.offset", offset*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI); - } - - /** - * Returns the bullet offset - */ - public int getBulletOffset() { - return getParaTextPropVal("bullet.offset")*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - - /** - * Sets the text offset - */ - public void setTextOffset(int offset) { - setParaTextPropVal("text.offset", offset*HSLFShape.MASTER_DPI/HSLFShape.POINT_DPI); - } - - /** - * Returns the text offset - */ - public int getTextOffset() { - return getParaTextPropVal("text.offset")*HSLFShape.POINT_DPI/HSLFShape.MASTER_DPI; - } - - /** - * Sets the bullet size - */ - public void setBulletSize(int size) { - setParaTextPropVal("bullet.size", size); - } - - /** - * Returns the bullet size - */ - public int getBulletSize() { - return getParaTextPropVal("bullet.size"); - } - - /** - * Sets the bullet color - */ - public void setBulletColor(Color color) { - int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 254).getRGB(); - setParaTextPropVal("bullet.color", rgb); - } - - /** - * Returns the bullet color - */ - public Color getBulletColor() { - int rgb = getParaTextPropVal("bullet.color"); - if(rgb == -1) return getFontColor(); - - int cidx = rgb >> 24; - if (rgb % 0x1000000 == 0){ - ColorSchemeAtom ca = parentParagraph.getSheet().getColorScheme(); - if(cidx >= 0 && cidx <= 7) rgb = ca.getColor(cidx); - } - Color tmp = new Color(rgb, true); - return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); - } - - /** - * Sets the bullet font - */ - public void setBulletFont(int idx) { - setParaTextPropVal("bullet.font", idx); - setFlag(false, ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, true); - } - - /** - * Returns the bullet font - */ - public int getBulletFont() { - return getParaTextPropVal("bullet.font"); - } - - /** - * Sets the line spacing. - *

    - * If linespacing >= 0, then linespacing is a percentage of normal line height. - * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates. - *

    - */ - public void setLineSpacing(int val) { - setParaTextPropVal("linespacing", val); - } - - /** - * Returns the line spacing - *

    - * If linespacing >= 0, then linespacing is a percentage of normal line height. - * If linespacing < 0, the absolute value of linespacing is the spacing in master coordinates. - *

    - * - * @return the spacing between lines - */ - public int getLineSpacing() { - int val = getParaTextPropVal("linespacing"); - return val == -1 ? 0 : val; - } - - /** - * Sets spacing before a paragraph. - *

    - * If spacebefore >= 0, then spacebefore is a percentage of normal line height. - * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates. - *

    - */ - public void setSpaceBefore(int val) { - setParaTextPropVal("spacebefore", val); - } - - /** - * Returns spacing before a paragraph - *

    - * If spacebefore >= 0, then spacebefore is a percentage of normal line height. - * If spacebefore < 0, the absolute value of spacebefore is the spacing in master coordinates. - *

    - * - * @return the spacing before a paragraph - */ - public int getSpaceBefore() { - int val = getParaTextPropVal("spacebefore"); - return val == -1 ? 0 : val; - } - - /** - * Sets spacing after a paragraph. - *

    - * If spaceafter >= 0, then spaceafter is a percentage of normal line height. - * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates. - *

    - */ - public void setSpaceAfter(int val) { - setParaTextPropVal("spaceafter", val); - } - - /** - * Returns spacing after a paragraph - *

    - * If spaceafter >= 0, then spaceafter is a percentage of normal line height. - * If spaceafter < 0, the absolute value of spaceafter is the spacing in master coordinates. - *

    - * - * @return the spacing before a paragraph - */ - public int getSpaceAfter() { - int val = getParaTextPropVal("spaceafter"); - return val == -1 ? 0 : val; - } - // --------------- Internal HSLF methods, not intended for end-user use! ------- - - /** - * Internal Use Only - get the underlying paragraph style collection. - * For normal use, use the friendly setters and getters - */ - public TextPropCollection _getRawParagraphStyle() { return paragraphStyle; } - /** - * Internal Use Only - get the underlying character style collection. - * For normal use, use the friendly setters and getters - */ - public TextPropCollection _getRawCharacterStyle() { return characterStyle; } - /** - * Internal Use Only - are the Paragraph styles shared? - */ - public boolean _isParagraphStyleShared() { return sharingParagraphStyle; } - /** - * Internal Use Only - are the Character styles shared? - */ - public boolean _isCharacterStyleShared() { return sharingCharacterStyle; } + public byte getPitchAndFamily() { + return 0; + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java new file mode 100644 index 0000000000..2c4e73b690 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java @@ -0,0 +1,754 @@ +/* ==================================================================== + 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 static org.apache.poi.hslf.record.RecordTypes.*; + +import java.awt.Rectangle; +import java.awt.font.FontRenderContext; +import java.awt.geom.Rectangle2D; +import java.awt.geom.Rectangle2D.Double; +import java.io.IOException; +import java.util.*; + +import org.apache.poi.POIXMLException; +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.exceptions.HSLFException; +import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.record.*; +import org.apache.poi.sl.draw.DrawFactory; +import org.apache.poi.sl.draw.DrawTextShape; +import org.apache.poi.sl.usermodel.*; +import org.apache.poi.util.POILogger; + +/** + * A common superclass of all shapes that can hold text. + * + * @author Yegor Kozlov + */ +public abstract class HSLFTextShape extends HSLFSimpleShape implements TextShape { + + /** + * How to anchor the text + */ + /* package */ static final int AnchorTop = 0; + /* package */ static final int AnchorMiddle = 1; + /* package */ static final int AnchorBottom = 2; + /* package */ static final int AnchorTopCentered = 3; + /* package */ static final int AnchorMiddleCentered = 4; + /* package */ static final int AnchorBottomCentered = 5; + /* package */ static final int AnchorTopBaseline = 6; + /* package */ static final int AnchorBottomBaseline = 7; + /* package */ static final int AnchorTopCenteredBaseline = 8; + /* package */ static final int AnchorBottomCenteredBaseline = 9; + + /** + * How to wrap the text + */ + public static final int WrapSquare = 0; + public static final int WrapByPoints = 1; + public static final int WrapNone = 2; + public static final int WrapTopBottom = 3; + public static final int WrapThrough = 4; + + /** + * TextRun object which holds actual text and format data + */ + protected List _paragraphs = new ArrayList(); + + /** + * Escher container which holds text attributes such as + * TextHeaderAtom, TextBytesAtom ot TextCharsAtom, StyleTextPropAtom etc. + */ + protected EscherTextboxWrapper _txtbox; + + /** + * This setting is used for supporting a deprecated alignment + * + * @see + */ + boolean alignToBaseline = false; + + /** + * Used to calculate text bounds + */ + protected static final FontRenderContext _frc = new FontRenderContext(null, true, true); + + /** + * Create a TextBox object and initialize it from the supplied Record container. + * + * @param escherRecord EscherSpContainer container which holds information about this shape + * @param parent the parent of the shape + */ + protected HSLFTextShape(EscherContainerRecord escherRecord, ShapeContainer parent){ + super(escherRecord, parent); + + } + + /** + * Create a new TextBox. This constructor is used when a new shape is created. + * + * @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 HSLFTextShape(ShapeContainer parent){ + super(null, parent); + _escherContainer = createSpContainer(parent instanceof HSLFGroupShape); + } + + /** + * Create a new TextBox. This constructor is used when a new shape is created. + * + */ + public HSLFTextShape(){ + this(null); + } + + /** + * Set default properties for the TextRun. + * Depending on the text and shape type the defaults are different: + * TextBox: align=left, valign=top + * AutoShape: align=center, valign=middle + * + */ + protected void setDefaultTextProperties(HSLFTextParagraph _txtrun){ + + } + + /** + * When a textbox is added to a sheet we need to tell upper-level + * PPDrawing about it. + * + * @param sh the sheet we are adding to + */ + protected void afterInsert(HSLFSheet sh){ + super.afterInsert(sh); + + EscherTextboxWrapper _txtbox = getEscherTextboxWrapper(); + if(_txtbox != null){ + PPDrawing ppdrawing = sh.getPPDrawing(); + ppdrawing.addTextboxWrapper(_txtbox); + // Ensure the escher layer knows about the added records + try { + _txtbox.writeOut(null); + } catch (IOException e){ + throw new HSLFException(e); + } + if(getAnchor().equals(new Rectangle()) && !"".equals(getText())) resizeToFitText(); + } + for (HSLFTextParagraph htp : _paragraphs) { + htp.setShapeId(getShapeId()); + } + sh.onAddTextShape(this); + } + + protected EscherTextboxWrapper getEscherTextboxWrapper(){ + if(_txtbox == null){ + EscherTextboxRecord textRecord = getEscherChild(EscherTextboxRecord.RECORD_ID); + if(textRecord != null) _txtbox = new EscherTextboxWrapper(textRecord); + } + return _txtbox; + } + + /** + * Adjust the size of the shape so it encompasses the text inside it. + * + * @return a Rectangle2D that is the bounds of this shape. + */ + public Rectangle2D resizeToFitText(){ + Rectangle2D anchor = getAnchor(); + if(anchor.getWidth() == 0.) { + logger.log(POILogger.WARN, "Width of shape wasn't set. Defaulting to 200px"); + anchor = new Rectangle2D.Double(anchor.getX(), anchor.getY(), 200, anchor.getHeight()); + setAnchor(anchor); + } + double height = getTextHeight(); + height += 1; // add a pixel to compensate rounding errors + + anchor.setRect(anchor.getX(), anchor.getY(), anchor.getWidth(), height); + setAnchor(anchor); + + return anchor; + } + + /** + * Returns the type of the text, from the TextHeaderAtom. + * Possible values can be seen from TextHeaderAtom + * @see org.apache.poi.hslf.record.TextHeaderAtom + */ + public int getRunType() { + getEscherTextboxWrapper(); + if (_txtbox == null) return -1; + TextHeaderAtom headerAtom = (TextHeaderAtom)_txtbox.findFirstOfType(TextHeaderAtom.typeID); + assert(headerAtom != null); + return headerAtom.getTextType(); + } + + /** + * Changes the type of the text. Values should be taken + * from TextHeaderAtom. No checking is done to ensure you + * set this to a valid value! + * @see org.apache.poi.hslf.record.TextHeaderAtom + */ + public void setRunType(int type) { + getEscherTextboxWrapper(); + if (_txtbox == null) return; + TextHeaderAtom headerAtom = (TextHeaderAtom)_txtbox.findFirstOfType(TextHeaderAtom.typeID); + assert(headerAtom != null); + headerAtom.setTextType(type); + } + + /** + * Returns the type of vertical alignment for the text. + * One of the Anchor* constants defined in this class. + * + * @return the type of alignment + */ + /* package */ int getAlignment(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT); + int align = HSLFTextShape.AnchorTop; + if (prop == null){ + /** + * If vertical alignment was not found in the shape properties then try to + * fetch the master shape and search for the align property there. + */ + int type = getRunType(); + HSLFMasterSheet master = getSheet().getMasterSheet(); + if(master != null){ + HSLFTextShape masterShape = master.getPlaceholderByTextType(type); + if(masterShape != null) align = masterShape.getAlignment(); + } else { + //not found in the master sheet. Use the hardcoded defaults. + switch (type){ + case org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE: + case org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE: + align = HSLFTextShape.AnchorMiddle; + break; + default: + align = HSLFTextShape.AnchorTop; + break; + } + } + } else { + align = prop.getPropertyValue(); + } + + alignToBaseline = (align == AnchorBottomBaseline || align == AnchorBottomCenteredBaseline + || align == AnchorTopBaseline || align == AnchorTopCenteredBaseline); + + return align; + } + + /** + * Sets the type of alignment for the text. + * One of the Anchor* constants defined in this class. + * + * @param align - the type of alignment + */ + /* package */ void setAlignment(Boolean isCentered, VerticalAlignment vAlign) { + int align[]; + switch (vAlign) { + case TOP: + align = new int[]{AnchorTop, AnchorTopCentered, AnchorTopBaseline, AnchorTopCenteredBaseline}; + break; + default: + case MIDDLE: + align = new int[]{AnchorMiddle, AnchorMiddleCentered, AnchorMiddle, AnchorMiddleCentered}; + break; + case BOTTOM: + align = new int[]{AnchorBottom, AnchorBottomCentered, AnchorBottomBaseline, AnchorBottomCenteredBaseline}; + break; + } + + int align2 = align[(isCentered ? 1 : 0)+(alignToBaseline ? 2 : 0)]; + + 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 + */ + public boolean isAlignToBaseline() { + getAlignment(); + return alignToBaseline; + } + + /** + * Sets the vertical alignment relative to the baseline + * + * @param alignToBaseline if true, vertical alignment is relative to baseline + */ + public void setAlignToBaseline(boolean alignToBaseline) { + this.alignToBaseline = alignToBaseline; + setAlignment(isHorizontalCentered(), getVerticalAlignment()); + } + + @Override + public boolean isHorizontalCentered() { + int va = getAlignment(); + switch (va) { + case AnchorTopCentered: + case AnchorTopCenteredBaseline: + case AnchorBottomCentered: + case AnchorBottomCenteredBaseline: + case AnchorMiddleCentered: + return true; + default: + return false; + } + } + + public void setVerticalAlignment(VerticalAlignment vAlign) { + setAlignment(isHorizontalCentered(), vAlign); + } + + /** + * 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()); + } + + /** + * Returns the distance (in points) between the bottom of the text frame + * and the bottom of the inscribed rectangle of the shape that contains the text. + * Default value is 1/20 inch. + * + * @return the botom margin + */ + public double getBottomInset(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTBOTTOM); + int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue(); + return val/EMU_PER_POINT; + } + + /** + * Sets the botom margin. + * @see #getBottomInset() + * + * @param margin the bottom margin + */ + public void setBottomInset(double margin){ + setEscherProperty(EscherProperties.TEXT__TEXTBOTTOM, (int)(margin*EMU_PER_POINT)); + } + + /** + * Returns the distance (in points) between the left edge of the text frame + * and the left edge of the inscribed rectangle of the shape that contains + * the text. + * Default value is 1/10 inch. + * + * @return the left margin + */ + public double getLeftInset(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTLEFT); + int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); + return val/EMU_PER_POINT; + } + + /** + * Sets the left margin. + * @see #getLeftInset() + * + * @param margin the left margin + */ + public void setLeftInset(double margin){ + setEscherProperty(EscherProperties.TEXT__TEXTLEFT, (int)(margin*EMU_PER_POINT)); + } + + /** + * Returns the distance (in points) between the right edge of the + * text frame and the right edge of the inscribed rectangle of the shape + * that contains the text. + * Default value is 1/10 inch. + * + * @return the right margin + */ + public double getRightInset(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTRIGHT); + int val = prop == null ? EMU_PER_INCH/10 : prop.getPropertyValue(); + return val/EMU_PER_POINT; + } + + /** + * Sets the right margin. + * @see #getRightInset() + * + * @param margin the right margin + */ + public void setRightInset(double margin){ + setEscherProperty(EscherProperties.TEXT__TEXTRIGHT, (int)(margin*EMU_PER_POINT)); + } + + /** + * Returns the distance (in points) between the top of the text frame + * and the top of the inscribed rectangle of the shape that contains the text. + * Default value is 1/20 inch. + * + * @return the top margin + */ + public double getTopInset(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTTOP); + int val = prop == null ? EMU_PER_INCH/20 : prop.getPropertyValue(); + return val/EMU_PER_POINT; + } + + /** + * Sets the top margin. + * @see #getTopInset() + * + * @param margin the top margin + */ + public void setTopInset(double margin){ + setEscherProperty(EscherProperties.TEXT__TEXTTOP, (int)(margin*EMU_PER_POINT)); + } + + @Override + public boolean getWordWrap(){ + int ww = getWordWrapEx(); + return (ww != WrapNone); + } + + /** + * Returns the value indicating word wrap. + * + * @return the value indicating word wrap. + * Must be one of the Wrap* constants defined in this class. + * + * @see MSOWRAPMODE + */ + public int getWordWrapEx() { + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__WRAPTEXT); + return prop == null ? WrapSquare : prop.getPropertyValue(); + } + + /** + * Specifies how the text should be wrapped + * + * @param wrap the value indicating how the text should be wrapped. + * Must be one of the Wrap* constants defined in this class. + */ + public void setWordWrap(int wrap){ + setEscherProperty(EscherProperties.TEXT__WRAPTEXT, wrap); + } + + /** + * @return id for the text. + */ + public int getTextId(){ + EscherOptRecord opt = getEscherOptRecord(); + EscherSimpleProperty prop = getEscherProperty(opt, EscherProperties.TEXT__TEXTID); + return prop == null ? 0 : prop.getPropertyValue(); + } + + /** + * Sets text ID + * + * @param id of the text + */ + public void setTextId(int id){ + setEscherProperty(EscherProperties.TEXT__TEXTID, id); + } + + /** + * @return the TextRun object for this text box + */ + public List getTextParagraphs(){ + if (!_paragraphs.isEmpty()) return _paragraphs; + + _txtbox = getEscherTextboxWrapper(); + if (_txtbox == null) { + _paragraphs.addAll(HSLFTextParagraph.createEmptyParagraph()); + _txtbox = _paragraphs.get(0).getTextboxWrapper(); + } else { + initParagraphsFromSheetRecords(); + if (_paragraphs.isEmpty()) { + List> llhtp = HSLFTextParagraph.findTextParagraphs(_txtbox); + if (!llhtp.isEmpty()) { + _paragraphs.addAll(llhtp.get(0)); + } + } + } + + for (HSLFTextParagraph p : _paragraphs) { + p.setParentShape(this); + } + + return _paragraphs; + } + + public void setSheet(HSLFSheet sheet) { + _sheet = sheet; + + // Initialize _txtrun object. + // (We can't do it in the constructor because the sheet + // is not assigned then, it's only built once we have + // all the records) + for (HSLFTextParagraph htp : getTextParagraphs()) { + // Supply the sheet to our child RichTextRuns + htp.supplySheet(_sheet); + } + } + + protected void initParagraphsFromSheetRecords(){ + EscherTextboxWrapper txtbox = getEscherTextboxWrapper(); + HSLFSheet sheet = getSheet(); + + if(sheet == null || txtbox == null) return; + + OutlineTextRefAtom ota = null; + + Record[] child = txtbox.getChildRecords(); + for (int i = 0; i < child.length; i++) { + if (child[i] instanceof OutlineTextRefAtom) { + ota = (OutlineTextRefAtom)child[i]; + break; + } + } + + List> sheetRuns = _sheet.getTextParagraphs(); + _paragraphs.clear(); + if (sheetRuns != null) { + if (ota != null) { + int idx = ota.getTextIndex(); + for (List r : sheetRuns) { + if (r.isEmpty()) continue; + int ridx = r.get(0).getIndex(); + if (ridx > idx) break; + if (ridx == idx) _paragraphs.addAll(r); + } + if(_paragraphs.isEmpty()) { + logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx); + } + } else { + int shapeId = getShapeId(); + for (List r : sheetRuns) { + if (r.isEmpty()) continue; + if (r.get(0).getShapeId() == shapeId) _paragraphs.addAll(r); + } + } + } + + // ensure the same references child records of TextRun + // TODO: check the purpose of this ... +// if(_txtrun != null) { +// for (int i = 0; i < child.length; i++) { +// for (Record r : _txtrun.getRecords()) { +// if (child[i].getRecordType() == r.getRecordType()) { +// child[i] = r; +// } +// } +// } +// } + } + + /* + // 0xB acts like cariage return in page titles and like blank in the others + char replChr; + switch(tha == null ? -1 : tha.getTextType()) { + case -1: + case TextHeaderAtom.TITLE_TYPE: + case TextHeaderAtom.CENTER_TITLE_TYPE: + replChr = '\n'; + break; + default: + replChr = ' '; + break; + } + + // PowerPoint seems to store files with \r as the line break + // The messes things up on everything but a Mac, so translate + // them to \n + String text = rawText.replace('\r','\n').replace('\u000b', replChr); + */ + + /** + * Return OEPlaceholderAtom, the atom that describes a placeholder. + * + * @return OEPlaceholderAtom or null if not found + */ + public OEPlaceholderAtom getPlaceholderAtom(){ + return getClientDataRecord(OEPlaceholderAtom.typeID); + } + + /** + * + * Assigns a hyperlink to this text shape + * + * @param linkId id of the hyperlink, @see org.apache.poi.hslf.usermodel.SlideShow#addHyperlink(Hyperlink) + * @param beginIndex the beginning index, inclusive. + * @param endIndex the ending index, exclusive. + * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#addHyperlink(HSLFHyperlink) + */ + public void setHyperlink(int linkId, int beginIndex, int endIndex){ + //TODO validate beginIndex and endIndex and throw IllegalArgumentException + + InteractiveInfo info = new InteractiveInfo(); + InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom(); + infoAtom.setAction(org.apache.poi.hslf.record.InteractiveInfoAtom.ACTION_HYPERLINK); + infoAtom.setHyperlinkType(org.apache.poi.hslf.record.InteractiveInfoAtom.LINK_Url); + infoAtom.setHyperlinkID(linkId); + + _txtbox.appendChildRecord(info); + + TxInteractiveInfoAtom txiatom = new TxInteractiveInfoAtom(); + txiatom.setStartIndex(beginIndex); + txiatom.setEndIndex(endIndex); + _txtbox.appendChildRecord(txiatom); + + } + + @Override + public boolean isPlaceholder() { + OEPlaceholderAtom oep = getPlaceholderAtom(); + if (oep != null) return true; + + //special case for files saved in Office 2007 + RoundTripHFPlaceholder12 hldr = getClientDataRecord(RoundTripHFPlaceholder12.typeID); + if (hldr != null) return true; + + return false; + } + + + @Override + public Iterator iterator() { + return _paragraphs.iterator(); + } + + @Override + public Insets2D getInsets() { + Insets2D insets = new Insets2D(getTopInset(), getLeftInset(), getBottomInset(), getRightInset()); + return insets; + } + + @Override + public double getTextHeight(){ + DrawFactory drawFact = DrawFactory.getInstance(null); + DrawTextShape dts = drawFact.getDrawable(this); + return dts.getTextHeight(); + } + + @Override + public TextDirection getTextDirection() { + // TODO: determine vertical text setting + return TextDirection.HORIZONTAL; + } + + /** + * Returns the raw text content of the shape. This hasn't had any + * changes applied to it, and so is probably unlikely to print + * out nicely. + */ + public String getRawText() { + return HSLFTextParagraph.getRawText(getTextParagraphs()); + } + + /** + * Returns the text contained in this text frame, which has been made safe + * for printing and other use. + * + * @return the text string for this textbox. + */ + public String getText() { + String rawText = getRawText(); + TextHeaderAtom _headerAtom = (TextHeaderAtom)_txtbox.findFirstOfType(TextHeaderAtom.typeID); + int runType = (_headerAtom == null) ? -1 : _headerAtom.getTextType(); + + return HSLFTextParagraph.toExternalString(rawText, runType); + } + + + // Update methods follow + + /** + * Adds the supplied text onto the end of the TextParagraphs, + * creating a new RichTextRun for it to sit in. + * + * @param text the text string used by this object. + */ + public void appendText(String text, boolean newParagraph) { + // init paragraphs + List paras = getTextParagraphs(); + 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. + */ + public void setText(String text) { + // init paragraphs + List paras = getTextParagraphs(); + HSLFTextParagraph.setText(paras, text); + setTextId(text.hashCode()); + } + + /** + * Saves the modified paragraphs/textrun to the records. + * Also updates the styles to the correct text length. + */ + protected void storeText() { + HSLFTextParagraph.storeText(_paragraphs); + } + // Accesser methods follow + + /** + * Returns the array of all hyperlinks in this text run + * + * @return the array of all hyperlinks in this text run or null + * if not found. + */ + public HSLFHyperlink[] getHyperlinks() { + return HSLFHyperlink.find(this); + } + + +} \ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTitleMaster.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTitleMaster.java new file mode 100644 index 0000000000..fc6131d952 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTitleMaster.java @@ -0,0 +1,71 @@ +/* ==================================================================== + 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 java.util.ArrayList; +import java.util.List; + +import org.apache.poi.hslf.model.textproperties.TextProp; +import org.apache.poi.hslf.record.SlideAtom; + +/** + * Title masters define the design template for slides with a Title Slide layout. + * + * @author Yegor Kozlov + */ +public final class HSLFTitleMaster extends HSLFMasterSheet { + private final List> _runs = new ArrayList>(); + + /** + * Constructs a TitleMaster + * + */ + public HSLFTitleMaster(org.apache.poi.hslf.record.Slide record, int sheetNo) { + super(record, sheetNo); + + _runs.addAll(HSLFTextParagraph.findTextParagraphs(getPPDrawing())); + } + + /** + * Returns an array of all the TextRuns found + */ + public List> getTextParagraphs() { + return _runs; + } + + /** + * Delegate the call to the underlying slide master. + */ + public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) { + HSLFMasterSheet master = getMasterSheet(); + return master == null ? null : master.getStyleAttribute(txtype, level, name, isCharacter); + } + + /** + * Returns the slide master for this title master. + */ + public HSLFMasterSheet getMasterSheet(){ + List master = getSlideShow().getSlideMasters(); + SlideAtom sa = ((org.apache.poi.hslf.record.Slide)getSheetContainer()).getSlideAtom(); + int masterId = sa.getMasterID(); + for (HSLFSlideMaster sm : master) { + if (masterId == sm._getSheetNumber()) return sm; + } + return null; + } +} diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/DrawFactory.java b/src/scratchpad/src/org/apache/poi/sl/draw/DrawFactory.java index bf82208cdc..df4d635a69 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/DrawFactory.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/DrawFactory.java @@ -76,7 +76,7 @@ public class DrawFactory { } else if (shape instanceof Background) { return getDrawable((Background)shape); } else if (shape instanceof Slide) { - return getDrawable((Slide)shape); + return getDrawable((Slide>)shape); } else if (shape instanceof MasterSheet) { return getDrawable((MasterSheet)shape); } else if (shape instanceof Sheet) { @@ -86,7 +86,7 @@ public class DrawFactory { throw new IllegalArgumentException("Unsupported shape type: "+shape.getClass()); } - public > DrawSlide getDrawable(T sheet) { + public >> DrawSlide getDrawable(T sheet) { return new DrawSlide(sheet); } diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/DrawSlide.java b/src/scratchpad/src/org/apache/poi/sl/draw/DrawSlide.java index cada314ece..4f5f631aee 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/DrawSlide.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/DrawSlide.java @@ -5,7 +5,7 @@ import java.awt.Graphics2D; import org.apache.poi.sl.usermodel.*; -public class DrawSlide> extends DrawSheet { +public class DrawSlide>> extends DrawSheet { public DrawSlide(T slide) { super(slide); diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java index 700edf0eb0..3db3c6f6d0 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -237,7 +237,7 @@ public class DrawTextParagraph implements Drawable { protected String getRenderableText(TextRun tr) { StringBuilder buf = new StringBuilder(); TextCap cap = tr.getTextCap(); - for (char c : tr.getText().toCharArray()) { + for (char c : tr.getRawText().toCharArray()) { if(c == '\t') { // TODO: finish support for tabs buf.append(" "); @@ -346,7 +346,7 @@ public class DrawTextParagraph implements Drawable { if(run.isItalic()) { attList.add(new AttributedStringData(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE, beginIndex, endIndex)); } - if(run.isUnderline()) { + if(run.isUnderlined()) { attList.add(new AttributedStringData(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON, beginIndex, endIndex)); attList.add(new AttributedStringData(TextAttribute.INPUT_METHOD_UNDERLINE, TextAttribute.UNDERLINE_LOW_TWO_PIXEL, beginIndex, endIndex)); } diff --git a/src/scratchpad/src/org/apache/poi/sl/draw/geom/PresetGeometries.java b/src/scratchpad/src/org/apache/poi/sl/draw/geom/PresetGeometries.java index 736dc0d668..e2caa084dd 100644 --- a/src/scratchpad/src/org/apache/poi/sl/draw/geom/PresetGeometries.java +++ b/src/scratchpad/src/org/apache/poi/sl/draw/geom/PresetGeometries.java @@ -19,8 +19,7 @@ package org.apache.poi.sl.draw.geom; -import java.io.*; -import java.nio.charset.Charset; +import java.io.InputStream; import java.util.LinkedHashMap; import javax.xml.bind.*; diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/Line.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/Line.java index 630c37de45..b06764e54d 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/Line.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/Line.java @@ -17,6 +17,6 @@ package org.apache.poi.sl.usermodel; -public interface Line extends AutoShape { +public interface Line> extends AutoShape { } diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/Notes.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/Notes.java index 08f023cd9f..3e4b924721 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/Notes.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/Notes.java @@ -20,5 +20,5 @@ package org.apache.poi.sl.usermodel; import java.util.List; public interface Notes extends Sheet { - List> getTextParagraphs(); + List>> getTextParagraphs(); } diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeContainer.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeContainer.java index 11a5039c66..1741a732d3 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeContainer.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeContainer.java @@ -17,18 +17,20 @@ package org.apache.poi.sl.usermodel; +import java.util.List; + public interface ShapeContainer extends Iterable { /** - * Returns an array containing all of the elements in this container in proper + * Returns an list containing all of the elements in this container in proper * sequence (from first to last element). * - * @return an array containing all of the elements in this container in proper + * @return an list containing all of the elements in this container in proper * sequence */ - public T[] getShapes(); + List getShapes(); - public void addShape(T shape); + void addShape(T shape); /** * Removes the specified shape from this sheet, if it is present @@ -40,5 +42,5 @@ public interface ShapeContainer extends Iterable { * @throws IllegalArgumentException if the type of the specified shape * is incompatible with this sheet (optional) */ - public boolean removeShape(T shape); + boolean removeShape(T shape); } diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeType.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeType.java index 0c25f5be4c..f151e0c082 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeType.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/ShapeType.java @@ -285,6 +285,25 @@ public enum ShapeType { this.nativeName = nativeName; } + /** name of the presetShapeDefinit(i)on entry */ + public String getOoxmlName() { + if (this == SEAL) return STAR_16.getOoxmlName(); + if (ooxmlId == -1) return null; + + StringBuilder sb = new StringBuilder(); + boolean toLower = true; + for (char ch : name().toCharArray()) { + if (ch == '_') { + toLower = false; + continue; + } + sb.append(toLower ? Character.toLowerCase(ch) : Character.toUpperCase(ch)); + toLower = true; + } + + return sb.toString(); + } + public static ShapeType forId(int id, boolean isOoxmlId){ for(ShapeType t : values()){ if((isOoxmlId && t.ooxmlId == id) || diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/Slide.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/Slide.java index b2027c182c..a9095c80ff 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/Slide.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/Slide.java @@ -17,16 +17,16 @@ package org.apache.poi.sl.usermodel; -public interface Slide extends Sheet { - public Notes getNotes(); - public void setNotes(Notes notes); +public interface Slide> extends Sheet { + N getNotes(); + void setNotes(N notes); - public boolean getFollowMasterBackground(); - public void setFollowMasterBackground(boolean follow); + boolean getFollowMasterBackground(); + void setFollowMasterBackground(boolean follow); - public boolean getFollowMasterColourScheme(); - public void setFollowMasterColourScheme(boolean follow); + boolean getFollowMasterColourScheme(); + void setFollowMasterColourScheme(boolean follow); - public boolean getFollowMasterObjects(); - public void setFollowMasterObjects(boolean follow); + boolean getFollowMasterObjects(); + void setFollowMasterObjects(boolean follow); } diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/SlideShow.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/SlideShow.java index e3007f6c17..ca0ddf3918 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/SlideShow.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/SlideShow.java @@ -19,13 +19,20 @@ package org.apache.poi.sl.usermodel; import java.awt.Dimension; import java.io.IOException; +import java.util.List; public interface SlideShow { - Slide createSlide() throws IOException; - MasterSheet createMasterSheet() throws IOException; + Slide> createSlide() throws IOException; - Slide[] getSlides(); - MasterSheet[] getMasterSheet(); + List>> getSlides(); + + MasterSheet createMasterSheet() throws IOException; + + /** + * Returns all slide masters. + * This doesn't include notes master and other arbitrary masters. + */ + List> getSlideMasters(); Resources getResources(); diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java index 348cc703d6..c4cf8bc57e 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextParagraph.java @@ -22,7 +22,7 @@ import java.awt.Color; public interface TextParagraph extends Iterable { /** - * Specified a list of text alignment types + * Specifies a list of text alignment types */ public enum TextAlign { /** @@ -50,6 +50,13 @@ public interface TextParagraph extends Iterable { THAI_DIST } + /** + * + */ + public enum FontAlign { + AUTO, TOP, CENTER, BASELINE, BOTTOM; + } + public interface BulletStyle { String getBulletCharacter(); String getBulletFont(); @@ -86,16 +93,32 @@ public interface TextParagraph extends Iterable { */ double getLeftMargin(); + /** + * @param leftMargin the left margin (in points) + */ + void setLeftMargin(double leftMargin); + + /** * @return the right margin (in points) of the paragraph */ double getRightMargin(); /** - * @return the indent applied (in points) to the first line of text in the paragraph. + * @param rightMargin the right margin (in points) of the paragraph + */ + void setRightMargin(double rightMargin); + + /** + * @return the indent (in points) applied to the first line of text in the paragraph. */ double getIndent(); + /** + * @param indent the indent (in points) applied to the first line of text in the paragraph + */ + void setIndent(double indent); + /** * Returns the vertical line spacing that is to be used within a paragraph. * This may be specified in two different ways, percentage spacing and font point spacing: @@ -123,6 +146,15 @@ public interface TextParagraph extends Iterable { */ TextAlign getTextAlign(); + + /** + * Returns the font alignment that is applied to the paragraph. + * + * If this attribute is omitted, then a value of auto (~ left) is implied. + * @return ??? alignment that is applied to the paragraph + */ + FontAlign getFontAlign(); + /** * @return the bullet style of the paragraph, if {@code null} then no bullets are used */ diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java index 87758c105f..8ac40c1892 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextRun.java @@ -31,7 +31,7 @@ public interface TextRun { ALL } - public String getText(); + public String getRawText(); public void setText(String text); TextCap getTextCap(); @@ -42,7 +42,7 @@ public interface TextRun { boolean isBold(); boolean isItalic(); - boolean isUnderline(); + boolean isUnderlined(); boolean isStrikethrough(); boolean isSubscript(); boolean isSuperscript(); diff --git a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextShape.java b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextShape.java index a6a53fe1bd..927fdf1f9d 100644 --- a/src/scratchpad/src/org/apache/poi/sl/usermodel/TextShape.java +++ b/src/scratchpad/src/org/apache/poi/sl/usermodel/TextShape.java @@ -17,6 +17,8 @@ package org.apache.poi.sl.usermodel; +import org.apache.poi.ss.usermodel.HorizontalAlignment; + public interface TextShape> extends SimpleShape, Iterable { @@ -104,6 +106,16 @@ public interface TextShape> extends S */ VerticalAlignment getVerticalAlignment(); + /** + * Returns if the text is centered. + * If true and if the individual paragraph settings allow it, + * the whole text block will be displayed centered, i.e. its left and right + * margin will be maximized while still keeping the alignment of the paragraphs + * + * @return true, if the text anchor is horizontal centered + */ + boolean isHorizontalCentered(); + /** * @return whether to wrap words within the bounding rectangle */ diff --git a/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java b/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java index 134f3e8ac0..652314c204 100644 --- a/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java +++ b/src/scratchpad/testcases/org/apache/poi/TestPOIDocumentScratchpad.java @@ -25,7 +25,7 @@ import junit.framework.TestCase; import java.io.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hwpf.HWPFTestDataSamples; import org.apache.poi.poifs.filesystem.*; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java b/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java index 6207a4597d..34d5aee93d 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/HSLFTestDataSamples.java @@ -24,8 +24,8 @@ import java.io.IOException; import java.io.InputStream; import org.apache.poi.POIDataSamples; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; public class HSLFTestDataSamples { diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestEncryptedFile.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestEncryptedFile.java index 3de6032ae5..ae43394273 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/TestEncryptedFile.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/TestEncryptedFile.java @@ -21,7 +21,7 @@ package org.apache.poi.hslf; import junit.framework.TestCase; import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.POIDataSamples; /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java index ae64b3614d..a742528e21 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWrite.java @@ -25,8 +25,8 @@ import java.io.FileNotFoundException; import junit.framework.TestCase; import org.apache.poi.POIDataSamples; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWriteSanity.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWriteSanity.java index 31a80ae306..50d2370d6a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/TestReWriteSanity.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/TestReWriteSanity.java @@ -23,8 +23,8 @@ import junit.framework.TestCase; import java.io.*; import java.util.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.poifs.filesystem.*; import org.apache.poi.POIDataSamples; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/TestRecordCounts.java b/src/scratchpad/testcases/org/apache/poi/hslf/TestRecordCounts.java index 732f609381..d40a1e6437 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/TestRecordCounts.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/TestRecordCounts.java @@ -20,8 +20,8 @@ package org.apache.poi.hslf; import junit.framework.TestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.POIDataSamples; /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java index a00d75d03e..55a4ca8bbd 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/extractor/TestExtractor.java @@ -23,9 +23,9 @@ import java.util.List; import org.apache.poi.POIDataSamples; import org.apache.poi.POITestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.model.OLEShape; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.poifs.filesystem.DirectoryNode; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java index 71cd5f570d..f43f168ee7 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/AllHSLFModelTests.java @@ -17,6 +17,7 @@ package org.apache.poi.hslf.model; +import org.apache.poi.hslf.usermodel.TestTextRun; import org.junit.runner.RunWith; import org.junit.runners.Suite; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java index 0d1cfd9e09..92eca1ae5d 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestBackground.java @@ -33,7 +33,7 @@ import org.apache.poi.ddf.EscherProperties; import org.apache.poi.ddf.EscherRecord; import org.apache.poi.ddf.EscherSimpleProperty; import org.apache.poi.hslf.record.Document; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeType; import org.junit.Test; @@ -53,7 +53,7 @@ public final class TestBackground { public void defaults() { HSLFSlideShow ppt = new HSLFSlideShow(); - assertEquals(HSLFFill.FILL_SOLID, ppt.getSlidesMasters()[0].getBackground().getFill().getFillType()); + assertEquals(HSLFFill.FILL_SOLID, ppt.getSlideMasters().get(0).getBackground().getFill().getFillType()); HSLFSlide slide = ppt.createSlide(); assertTrue(slide.getFollowMasterBackground()); @@ -72,26 +72,26 @@ public final class TestBackground { HSLFFill fill; HSLFShape shape; - HSLFSlide[] slide = ppt.getSlides(); + List slide = ppt.getSlides(); - fill = slide[0].getBackground().getFill(); + fill = slide.get(0).getBackground().getFill(); assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType()); - shape = slide[0].getShapes()[0]; + shape = slide.get(0).getShapes().get(0); assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType()); - fill = slide[1].getBackground().getFill(); + fill = slide.get(1).getBackground().getFill(); assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType()); - shape = slide[1].getShapes()[0]; + shape = slide.get(1).getShapes().get(0); assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType()); - fill = slide[2].getBackground().getFill(); + fill = slide.get(2).getBackground().getFill(); assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType()); - shape = slide[2].getShapes()[0]; + shape = slide.get(2).getShapes().get(0); assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType()); - fill = slide[3].getBackground().getFill(); + fill = slide.get(3).getBackground().getFill(); assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType()); - shape = slide[3].getShapes()[0]; + shape = slide.get(3).getShapes().get(0); assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType()); } @@ -174,29 +174,29 @@ public final class TestBackground { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - HSLFSlide[] slides = ppt.getSlides(); + List slides = ppt.getSlides(); - fill = slides[0].getBackground().getFill(); + fill = slides.get(0).getBackground().getFill(); assertEquals(HSLFFill.FILL_PICTURE, fill.getFillType()); - assertEquals(3, getFillPictureRefCount(slides[0].getBackground(), fill)); - shape = slides[0].getShapes()[0]; + assertEquals(3, getFillPictureRefCount(slides.get(0).getBackground(), fill)); + shape = slides.get(0).getShapes().get(0); assertEquals(HSLFFill.FILL_SOLID, shape.getFill().getFillType()); - fill = slides[1].getBackground().getFill(); + fill = slides.get(1).getBackground().getFill(); assertEquals(HSLFFill.FILL_PATTERN, fill.getFillType()); - shape = slides[1].getShapes()[0]; + shape = slides.get(1).getShapes().get(0); assertEquals(HSLFFill.FILL_BACKGROUND, shape.getFill().getFillType()); - fill = slides[2].getBackground().getFill(); + fill = slides.get(2).getBackground().getFill(); assertEquals(HSLFFill.FILL_TEXTURE, fill.getFillType()); - assertEquals(3, getFillPictureRefCount(slides[2].getBackground(), fill)); - shape = slides[2].getShapes()[0]; + assertEquals(3, getFillPictureRefCount(slides.get(2).getBackground(), fill)); + shape = slides.get(2).getShapes().get(0); assertEquals(HSLFFill.FILL_PICTURE, shape.getFill().getFillType()); assertEquals(1, getFillPictureRefCount(shape, fill)); - fill = slides[3].getBackground().getFill(); + fill = slides.get(3).getBackground().getFill(); assertEquals(HSLFFill.FILL_SHADE_CENTER, fill.getFillType()); - shape = slides[3].getShapes()[0]; + shape = slides.get(3).getShapes().get(0); assertEquals(HSLFFill.FILL_SHADE, shape.getFill().getFillType()); } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java index 6d1365efbe..cdbf28cb60 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestFreeform.java @@ -17,12 +17,13 @@ package org.apache.poi.hslf.model; -import java.awt.geom.Area; -import java.awt.geom.GeneralPath; -import java.awt.geom.Line2D; -import java.awt.geom.Rectangle2D; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import junit.framework.TestCase; +import java.awt.geom.*; + +import org.apache.poi.hslf.usermodel.HSLFFreeformShape; +import org.junit.Test; /** * Test Freeform object. @@ -32,8 +33,9 @@ import junit.framework.TestCase; * * @author Yegor Kozlov */ -public final class TestFreeform extends TestCase { +public final class TestFreeform { + @Test public void testClosedPath() { GeneralPath path1 = new GeneralPath(); @@ -50,6 +52,7 @@ public final class TestFreeform extends TestCase { assertTrue(new Area(path1).equals(new Area(path2))); } + @Test public void testLine() { GeneralPath path1 = new GeneralPath(new Line2D.Double(100, 100, 200, 100)); @@ -61,6 +64,7 @@ public final class TestFreeform extends TestCase { assertTrue(new Area(path1).equals(new Area(path2))); } + @Test public void testRectangle() { GeneralPath path1 = new GeneralPath(new Rectangle2D.Double(100, 100, 200, 50)); @@ -76,6 +80,7 @@ public final class TestFreeform extends TestCase { * Avoid NPE in Freeform.getOutline() if either GEOMETRY__VERTICES or * GEOMETRY__SEGMENTINFO is missing, see Bugzilla 54188 */ + @Test public void test54188() { HSLFFreeformShape p = new HSLFFreeformShape(); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java index 8239a359d5..6a503fde4a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHeadersFooters.java @@ -17,22 +17,27 @@ package org.apache.poi.hslf.model; -import java.io.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.List; -import junit.framework.TestCase; +import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.HSLFSlide; +import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.junit.Test; /** * Test {@link org.apache.poi.hslf.model.HeadersFooters} object */ -public final class TestHeadersFooters extends TestCase +public final class TestHeadersFooters { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); - public void testRead() throws Exception - { + @Test + public void testRead() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("headers_footers.ppt")); HeadersFooters slideHdd = ppt.getSlideHeadersFooters(); @@ -53,9 +58,9 @@ public final class TestHeadersFooters extends TestCase assertTrue(notesHdd.isUserDateVisible()); assertNull(notesHdd.getDateTimeText()); - HSLFSlide[] slide = ppt.getSlides(); + List slide = ppt.getSlides(); //the first slide uses presentation-scope headers / footers - HeadersFooters hd1 = slide[0].getHeadersFooters(); + HeadersFooters hd1 = slide.get(0).getHeadersFooters(); assertEquals(slideHdd.isFooterVisible(), hd1.isFooterVisible()); assertEquals(slideHdd.getFooterText(), hd1.getFooterText()); assertEquals(slideHdd.isSlideNumberVisible(), hd1.isSlideNumberVisible()); @@ -65,7 +70,7 @@ public final class TestHeadersFooters extends TestCase assertEquals(slideHdd.getDateTimeText(), hd1.getDateTimeText()); //the first slide uses per-slide headers / footers - HeadersFooters hd2 = slide[1].getHeadersFooters(); + HeadersFooters hd2 = slide.get(1).getHeadersFooters(); assertEquals(true, hd2.isFooterVisible()); assertEquals("per-slide footer", hd2.getFooterText()); assertEquals(true, hd2.isUserDateVisible()); @@ -75,8 +80,8 @@ public final class TestHeadersFooters extends TestCase /** * If Headers / Footers are not set, all the getters should return false or null */ - public void testReadNoHeadersFooters() throws Exception - { + @Test + public void testReadNoHeadersFooters() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("basic_test_ppt_file.ppt")); HeadersFooters slideHdd = ppt.getSlideHeadersFooters(); @@ -97,9 +102,8 @@ public final class TestHeadersFooters extends TestCase assertFalse(notesHdd.isUserDateVisible()); assertNull(notesHdd.getDateTimeText()); - HSLFSlide[] slide = ppt.getSlides(); - for(int i=0 ; i < slide.length; i++){ - HeadersFooters hd1 = slide[i].getHeadersFooters(); + for(HSLFSlide s : ppt.getSlides()) { + HeadersFooters hd1 = s.getHeadersFooters(); assertFalse(hd1.isFooterVisible()); assertNull(hd1.getFooterText()); assertFalse(hd1.isHeaderVisible()); @@ -112,8 +116,8 @@ public final class TestHeadersFooters extends TestCase /** * Test extraction of headers / footers from PPTs saved in Office 2007 */ - public void testRead2007() throws Exception - { + @Test + public void testRead2007() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("headers_footers_2007.ppt")); HeadersFooters slideHdd = ppt.getSlideHeadersFooters(); @@ -137,9 +141,9 @@ public final class TestHeadersFooters extends TestCase //assertEquals("08/12/08", notesHdd.getDateTimeText()); //per-slide headers / footers - HSLFSlide[] slide = ppt.getSlides(); + List slide = ppt.getSlides(); //the first slide uses presentation-scope headers / footers - HeadersFooters hd1 = slide[0].getHeadersFooters(); + HeadersFooters hd1 = slide.get(0).getHeadersFooters(); assertTrue(hd1.isFooterVisible()); assertEquals("THE FOOTER TEXT", hd1.getFooterText()); assertTrue(hd1.isSlideNumberVisible()); @@ -150,7 +154,7 @@ public final class TestHeadersFooters extends TestCase assertEquals("Wednesday, August 06, 2008", hd1.getDateTimeText()); //the second slide uses custom per-slide headers / footers - HeadersFooters hd2 = slide[1].getHeadersFooters(); + HeadersFooters hd2 = slide.get(1).getHeadersFooters(); assertTrue(hd2.isFooterVisible()); assertEquals("THE FOOTER TEXT FOR SLIDE 2", hd2.getFooterText()); assertTrue(hd2.isSlideNumberVisible()); @@ -161,7 +165,7 @@ public final class TestHeadersFooters extends TestCase assertEquals("August 06, 2008", hd2.getDateTimeText()); //the third slide uses per-slide headers / footers - HeadersFooters hd3 = slide[2].getHeadersFooters(); + HeadersFooters hd3 = slide.get(2).getHeadersFooters(); assertTrue(hd3.isFooterVisible()); assertEquals("THE FOOTER TEXT", hd3.getFooterText()); assertTrue(hd3.isSlideNumberVisible()); @@ -172,8 +176,8 @@ public final class TestHeadersFooters extends TestCase assertEquals("Wednesday, August 06, 2008", hd3.getDateTimeText()); } - public void testCreateSlideFooters() throws Exception - { + @Test + public void testCreateSlideFooters() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(); HeadersFooters hdd = ppt.getSlideHeadersFooters(); hdd.setFootersText("My slide footer"); @@ -190,8 +194,8 @@ public final class TestHeadersFooters extends TestCase assertEquals("My slide footer", hdd2.getFooterText()); } - public void testCreateNotesFooters() throws Exception - { + @Test + public void testCreateNotesFooters() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(); HeadersFooters hdd = ppt.getNotesHeadersFooters(); hdd.setFootersText("My notes footer"); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java index 83e6ca6582..5438ac8af9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java @@ -17,70 +17,68 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; +import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.getRawText; +import static org.apache.poi.hslf.usermodel.HSLFTextParagraph.toExternalString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import java.util.List; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test Hyperlink. * * @author Yegor Kozlov */ -public final class TestHyperlink extends TestCase { +public final class TestHyperlink { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); + @Test public void testTextRunHyperlinks() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("WithLinks.ppt")); - HSLFTextParagraph[] run; - HSLFSlide slide; - slide = ppt.getSlides()[0]; - run = slide.getTextRuns(); - for (int i = 0; i < run.length; i++) { - String text = run[i].getText(); - if (text.equals( - "This page has two links:\n" + - "http://jakarta.apache.org/poi/\n" + - "\n" + - "http://slashdot.org/\n" + - "\n" + - "In addition, its notes has one link")){ - - Hyperlink[] links = run[i].getHyperlinks(); - assertNotNull(links); - assertEquals(2, links.length); - - assertEquals("http://jakarta.apache.org/poi/", links[0].getTitle()); - assertEquals("http://jakarta.apache.org/poi/", links[0].getAddress()); - assertEquals("http://jakarta.apache.org/poi/", text.substring(links[0].getStartIndex(), links[0].getEndIndex()-1)); - - assertEquals("http://slashdot.org/", links[1].getTitle()); - assertEquals("http://slashdot.org/", links[1].getAddress()); - assertEquals("http://slashdot.org/", text.substring(links[1].getStartIndex(), links[1].getEndIndex()-1)); - - } - } - - slide = ppt.getSlides()[1]; - run = slide.getTextRuns(); - for (int i = 0; i < run.length; i++) { - String text = run[i].getText(); - if (text.equals( - "I have the one link:\n" + - "Jakarta HSSF")){ - - Hyperlink[] links = run[i].getHyperlinks(); - assertNotNull(links); - assertEquals(1, links.length); - - assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getTitle()); - assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getAddress()); - assertEquals("Jakarta HSSF", text.substring(links[0].getStartIndex(), links[0].getEndIndex()-1)); - - } - } - + HSLFSlide slide = ppt.getSlides().get(0); + List para = slide.getTextParagraphs().get(1); + + String rawText = toExternalString(getRawText(para), para.get(0).getRunType()); + String expected = + "This page has two links:\n"+ + "http://jakarta.apache.org/poi/\n"+ + "\n"+ + "http://slashdot.org/\n"+ + "\n"+ + "In addition, its notes has one link"; + assertEquals(expected, rawText); + + HSLFHyperlink[] links = HSLFHyperlink.find(para.get(1)); + assertNotNull(links); + assertEquals(2, links.length); + + assertEquals("http://jakarta.apache.org/poi/", links[0].getTitle()); + assertEquals("http://jakarta.apache.org/poi/", links[0].getAddress()); + assertEquals("http://jakarta.apache.org/poi/", rawText.substring(links[0].getStartIndex(), links[0].getEndIndex()-1)); + + assertEquals("http://slashdot.org/", links[1].getTitle()); + assertEquals("http://slashdot.org/", links[1].getAddress()); + assertEquals("http://slashdot.org/", rawText.substring(links[1].getStartIndex(), links[1].getEndIndex()-1)); + + slide = ppt.getSlides().get(1); + para = slide.getTextParagraphs().get(1); + rawText = toExternalString(getRawText(para), para.get(0).getRunType()); + expected = + "I have the one link:\n" + + "Jakarta HSSF"; + assertEquals(expected, rawText); + + links = HSLFHyperlink.find(para.get(1)); + assertNotNull(links); + assertEquals(1, links.length); + + assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getTitle()); + assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getAddress()); + assertEquals("Jakarta HSSF", rawText.substring(links[0].getStartIndex(), links[0].getEndIndex()-1)); } - } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestImagePainter.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestImagePainter.java index 11a64f6379..963beeefbe 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestImagePainter.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestImagePainter.java @@ -24,6 +24,7 @@ import junit.framework.TestCase; import org.apache.poi.hslf.blip.BitmapPainter; import org.apache.poi.hslf.blip.ImagePainter; import org.apache.poi.hslf.usermodel.HSLFPictureData; +import org.apache.poi.hslf.usermodel.HSLFPictureShape; /** * Test Picture shape. diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java index 413ff8ebe8..5d58b25383 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestLine.java @@ -19,17 +19,20 @@ package org.apache.poi.hslf.model; import java.awt.Color; -import junit.framework.TestCase; - +import org.apache.poi.hslf.usermodel.HSLFSlide; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.sl.usermodel.StrokeStyle.LineCompound; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; +import org.junit.Test; /** * Test Line shape. * * @author Yegor Kozlov */ -public final class TestLine extends TestCase { +public final class TestLine { + @Test public void testCreateLines() { HSLFSlideShow ppt = new HSLFSlideShow(); @@ -44,31 +47,31 @@ public final class TestLine extends TestCase { */ line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 200, 300, 0)); - line.setLineStyle(Line.LINE_SIMPLE); + line.setLineCompound(LineCompound.SINGLE); line.setLineColor(Color.blue); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 230, 300, 0)); - line.setLineStyle(Line.LINE_DOUBLE); + line.setLineCompound(LineCompound.DOUBLE); line.setLineWidth(3.5); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 260, 300, 0)); - line.setLineStyle(Line.LINE_TRIPLE); + line.setLineCompound(LineCompound.TRIPLE); line.setLineWidth(6); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 290, 300, 0)); - line.setLineStyle(Line.LINE_THICKTHIN); + line.setLineCompound(LineCompound.THICK_THIN); line.setLineWidth(4.5); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 320, 300, 0)); - line.setLineStyle(Line.LINE_THINTHICK); + line.setLineCompound(LineCompound.THIN_THICK); line.setLineWidth(5.5); slide.addShape(line); @@ -77,27 +80,27 @@ public final class TestLine extends TestCase { */ line = new Line(); line.setAnchor(new java.awt.Rectangle(450, 200, 300, 0)); - line.setLineDashing(Line.PEN_SOLID); + line.setLineDashing(LineDash.SOLID); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(450, 230, 300, 0)); - line.setLineDashing(Line.PEN_PS_DASH); + line.setLineDashing(LineDash.DASH); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(450, 260, 300, 0)); - line.setLineDashing(Line.PEN_DOT); + line.setLineDashing(LineDash.DOT); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(450, 290, 300, 0)); - line.setLineDashing(Line.PEN_DOTGEL); + line.setLineDashing(LineDash.DASH_DOT); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(450, 320, 300, 0)); - line.setLineDashing(Line.PEN_LONGDASHDOTDOTGEL); + line.setLineDashing(LineDash.LG_DASH_DOT_DOT); slide.addShape(line); /** @@ -105,22 +108,22 @@ public final class TestLine extends TestCase { */ line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 400, 300, 0)); - line.setLineDashing(Line.PEN_DASHDOT); - line.setLineStyle(Line.LINE_TRIPLE); + line.setLineDashing(LineDash.DASH_DOT); + line.setLineCompound(LineCompound.TRIPLE); line.setLineWidth(5.0); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 430, 300, 0)); - line.setLineDashing(Line.PEN_DASH); - line.setLineStyle(Line.LINE_THICKTHIN); + line.setLineDashing(LineDash.DASH); + line.setLineCompound(LineCompound.THICK_THIN); line.setLineWidth(4.0); slide.addShape(line); line = new Line(); line.setAnchor(new java.awt.Rectangle(75, 460, 300, 0)); - line.setLineDashing(Line.PEN_DOT); - line.setLineStyle(Line.LINE_DOUBLE); + line.setLineDashing(LineDash.DOT); + line.setLineCompound(LineCompound.DOUBLE); line.setLineWidth(8.0); slide.addShape(line); } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java index 1b5bbd3298..a83d820123 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestMovieShape.java @@ -17,24 +17,26 @@ package org.apache.poi.hslf.model; +import static org.junit.Assert.*; + import java.awt.geom.Rectangle2D; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; -import junit.framework.TestCase; - -import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test MovieShape object. * * @author Yegor Kozlov */ -public final class TestMovieShape extends TestCase { +public final class TestMovieShape { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); + @Test public void testCreate() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(); @@ -57,8 +59,8 @@ public final class TestMovieShape extends TestCase { ppt.write(out); ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); - slide = ppt.getSlides()[0]; - shape = (MovieShape)slide.getShapes()[0]; + slide = ppt.getSlides().get(0); + shape = (MovieShape)slide.getShapes().get(0); assertEquals(path, shape.getPath()); assertFalse(shape.isAutoPlay()); } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java index 410f48226a..f58949117f 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestOleEmbedding.java @@ -18,32 +18,28 @@ package org.apache.poi.hslf.model; import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; import java.awt.geom.Rectangle2D; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.InputStream; - -import junit.framework.TestCase; +import java.io.*; import org.apache.poi.POIDataSamples; -import org.apache.poi.hslf.usermodel.HSLFObjectData; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hwpf.HWPFDocument; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.apache.poi.util.IOUtils; +import org.junit.Test; -public final class TestOleEmbedding extends TestCase { +public final class TestOleEmbedding { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); /** * Tests support for OLE objects. * * @throws Exception if an error occurs. */ + @Test public void testOleEmbedding2003() throws Exception { HSLFSlideShowImpl slideShow = new HSLFSlideShowImpl(_slTests.openResourceAsStream("ole2-embedding-2003.ppt")); // Placeholder EMFs for clients that don't support the OLE components. @@ -59,16 +55,16 @@ public final class TestOleEmbedding extends TestCase { //assertDigestEquals("Wrong data for object 2", "b323604b2003a7299c77c2693b641495", objects[1].getData()); } + @Test public void testOLEShape() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("ole2-embedding-2003.ppt")); - HSLFSlide slide = ppt.getSlides()[0]; - HSLFShape[] sh = slide.getShapes(); + HSLFSlide slide = ppt.getSlides().get(0); int cnt = 0; - for (int i = 0; i < sh.length; i++) { - if(sh[i] instanceof OLEShape){ + for (HSLFShape sh : slide.getShapes()) { + if(sh instanceof OLEShape){ cnt++; - OLEShape ole = (OLEShape)sh[i]; + OLEShape ole = (OLEShape)sh; HSLFObjectData data = ole.getObjectData(); if("Worksheet".equals(ole.getInstanceName())){ //Voila! we created a workbook from the embedded OLE data @@ -80,6 +76,7 @@ public final class TestOleEmbedding extends TestCase { assertEquals(2, sheet.getRow(2).getCell(0).getNumericCellValue(), 0); assertEquals(3, sheet.getRow(3).getCell(0).getNumericCellValue(), 0); assertEquals(8, sheet.getRow(5).getCell(0).getNumericCellValue(), 0); + wb.close(); } else if ("Document".equals(ole.getInstanceName())){ //creating a HWPF document HWPFDocument doc = new HWPFDocument(data.getData()); @@ -92,6 +89,7 @@ public final class TestOleEmbedding extends TestCase { assertEquals("Expected 2 OLE shapes", 2, cnt); } + @Test public void testEmbedding() throws Exception { HSLFSlideShowImpl _hslfSlideShow = HSLFSlideShowImpl.create(); HSLFSlideShow ppt = new HSLFSlideShow(_hslfSlideShow); @@ -129,7 +127,7 @@ public final class TestOleEmbedding extends TestCase { ppt.write(bos); ppt = new HSLFSlideShow(new ByteArrayInputStream(bos.toByteArray())); - OLEShape comp = (OLEShape)ppt.getSlides()[0].getShapes()[0]; + OLEShape comp = (OLEShape)ppt.getSlides().get(0).getShapes().get(0); byte compData[] = IOUtils.toByteArray(comp.getObjectData().getData()); bos.reset(); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java index fb04ccf5dd..4c69862c3b 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPFont.java @@ -17,16 +17,20 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; + import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.junit.Test; + /** * Test adding fonts to the presenataion resources * * @author Yegor Kozlov */ -public final class TestPPFont extends TestCase{ +public final class TestPPFont { + @Test public void testCreate() { HSLFSlideShow ppt = new HSLFSlideShow(); assertEquals(1, ppt.getNumberOfFonts()); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java index b71ce01035..4fb06ddcf3 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPPGraphics2D.java @@ -17,35 +17,41 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; - -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import java.awt.*; -import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.List; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Before; +import org.junit.Test; /** * Test drawing shapes via Graphics2D * * @author Yegor Kozlov */ -public final class TestPPGraphics2D extends TestCase { +public final class TestPPGraphics2D { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); private HSLFSlideShow ppt; + @Before protected void setUp() throws Exception { ppt = new HSLFSlideShow(_slTests.openResourceAsStream("empty.ppt")); } + @Test public void testGraphics() throws Exception { // Starts off empty - assertEquals(0, ppt.getSlides().length); + assertTrue(ppt.getSlides().isEmpty()); // Add a slide HSLFSlide slide = ppt.createSlide(); - assertEquals(1, ppt.getSlides().length); + assertEquals(1, ppt.getSlides().size()); // Add some stuff into it HSLFGroupShape group = new HSLFGroupShape(); @@ -73,17 +79,17 @@ public final class TestPPGraphics2D extends TestCase { // And read it back in ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertEquals(1, ppt.getSlides().length); + assertEquals(1, ppt.getSlides().size()); - slide = ppt.getSlides()[0]; - HSLFShape[] shape = slide.getShapes(); - assertEquals(shape.length, 1); //group shape + slide = ppt.getSlides().get(0); + List shape = slide.getShapes(); + assertEquals(shape.size(), 1); //group shape - assertTrue(shape[0] instanceof HSLFGroupShape); //group shape + assertTrue(shape.get(0) instanceof HSLFGroupShape); //group shape - group = (HSLFGroupShape)shape[0]; + group = (HSLFGroupShape)shape.get(0); shape = group.getShapes(); - assertEquals(shape.length, 3); + assertEquals(shape.size(), 3); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java index 08077f0e00..ff4e1c5a7a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestPicture.java @@ -36,8 +36,7 @@ import javax.imageio.ImageIO; import org.apache.poi.POIDataSamples; import org.apache.poi.ddf.EscherBSERecord; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.util.JvmBugs; import org.junit.Ignore; import org.junit.Test; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSetBoldItalic.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSetBoldItalic.java index e1703626ca..febf9e3b20 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSetBoldItalic.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSetBoldItalic.java @@ -17,24 +17,25 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; +import static org.junit.Assert.*; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.hslf.usermodel.HSLFTextRun; - -import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test setting text properties of newly added TextBoxes * * @author Yegor Kozlov */ -public final class TestSetBoldItalic extends TestCase { +public final class TestSetBoldItalic { /** * Verify that we can add TextBox shapes to a slide * and set some of the style attributes */ + @Test public void testTextBoxWrite() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide sl = ppt.createSlide(); @@ -44,7 +45,7 @@ public final class TestSetBoldItalic extends TestCase { // Create a new textbox, and give it lots of properties HSLFTextBox txtbox = new HSLFTextBox(); - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); txtbox.setText(val); rt.setFontSize(42); rt.setBold(true); @@ -53,9 +54,9 @@ public final class TestSetBoldItalic extends TestCase { sl.addShape(txtbox); // Check it before save - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; - assertEquals(val, rt.getText()); - assertEquals(42, rt.getFontSize()); + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(val, rt.getRawText()); + assertEquals(42, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); @@ -65,14 +66,14 @@ public final class TestSetBoldItalic extends TestCase { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - sl = ppt.getSlides()[0]; + sl = ppt.getSlides().get(0); - txtbox = (HSLFTextBox)sl.getShapes()[0]; - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; + txtbox = (HSLFTextBox)sl.getShapes().get(0); + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); // Check after save - assertEquals(val, rt.getText()); - assertEquals(42, rt.getFontSize()); + assertEquals(val, rt.getRawText()); + assertEquals(42, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); assertFalse(rt.isUnderlined()); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java index 9456c211f8..d38a21ecab 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestShapes.java @@ -17,30 +17,18 @@ package org.apache.poi.hslf.model; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Rectangle; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; +import static org.junit.Assert.*; + +import java.awt.*; +import java.io.*; import java.util.ArrayList; +import java.util.List; import org.apache.poi.POIDataSamples; -import org.apache.poi.ddf.EscherDgRecord; -import org.apache.poi.ddf.EscherDggRecord; -import org.apache.poi.ddf.EscherOptRecord; -import org.apache.poi.ddf.EscherProperties; -import org.apache.poi.ddf.EscherSimpleProperty; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.ddf.*; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeType; +import org.apache.poi.sl.usermodel.StrokeStyle.LineDash; import org.junit.Before; import org.junit.Test; @@ -77,7 +65,7 @@ public final class TestShapes { java.awt.Rectangle lineAnchor = new java.awt.Rectangle(100, 200, 50, 60); line.setAnchor(lineAnchor); line.setLineWidth(3); - line.setLineStyle(Line.PEN_DASH); + line.setLineDashing(LineDash.DASH); line.setLineColor(Color.red); slide.addShape(line); @@ -85,7 +73,7 @@ public final class TestShapes { java.awt.Rectangle ellipseAnchor = new Rectangle(320, 154, 55, 111); ellipse.setAnchor(ellipseAnchor); ellipse.setLineWidth(2); - ellipse.setLineStyle(Line.PEN_SOLID); + ellipse.setLineDashing(LineDash.SOLID); ellipse.setLineColor(Color.green); ellipse.setFillColor(Color.lightGray); slide.addShape(ellipse); @@ -97,17 +85,17 @@ public final class TestShapes { //read ppt from byte array ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertEquals(1, ppt.getSlides().length); + assertEquals(1, ppt.getSlides().size()); - slide = ppt.getSlides()[0]; - HSLFShape[] shape = slide.getShapes(); - assertEquals(2, shape.length); + slide = ppt.getSlides().get(0); + List shape = slide.getShapes(); + assertEquals(2, shape.size()); - assertTrue(shape[0] instanceof Line); //group shape - assertEquals(lineAnchor, shape[0].getAnchor()); //group shape + assertTrue(shape.get(0) instanceof Line); //group shape + assertEquals(lineAnchor, shape.get(0).getAnchor()); //group shape - assertTrue(shape[1] instanceof HSLFAutoShape); //group shape - assertEquals(ellipseAnchor, shape[1].getAnchor()); //group shape + assertTrue(shape.get(1) instanceof HSLFAutoShape); //group shape + assertEquals(ellipseAnchor, shape.get(1).getAnchor()); //group shape } /** @@ -117,31 +105,30 @@ public final class TestShapes { @Test public void textBoxRead() throws Exception { ppt = new HSLFSlideShow(_slTests.openResourceAsStream("with_textbox.ppt")); - HSLFSlide sl = ppt.getSlides()[0]; - HSLFShape[] sh = sl.getShapes(); - for (int i = 0; i < sh.length; i++) { - assertTrue(sh[i] instanceof HSLFTextBox); - HSLFTextBox txtbox = (HSLFTextBox)sh[i]; + HSLFSlide sl = ppt.getSlides().get(0); + for (HSLFShape sh : sl.getShapes()) { + assertTrue(sh instanceof HSLFTextBox); + HSLFTextBox txtbox = (HSLFTextBox)sh; String text = txtbox.getText(); assertNotNull(text); - assertEquals(txtbox.getTextParagraph().getRichTextRuns().length, 1); - HSLFTextRun rt = txtbox.getTextParagraph().getRichTextRuns()[0]; + assertEquals(txtbox.getTextParagraphs().get(0).getTextRuns().size(), 1); + HSLFTextRun rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); if (text.equals("Hello, World!!!")){ - assertEquals(32, rt.getFontSize()); + assertEquals(32, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); } else if (text.equals("I am just a poor boy")){ - assertEquals(44, rt.getFontSize()); + assertEquals(44, rt.getFontSize(), 0); assertTrue(rt.isBold()); } else if (text.equals("This is Times New Roman")){ - assertEquals(16, rt.getFontSize()); + assertEquals(16, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); assertTrue(rt.isUnderlined()); } else if (text.equals("Plain Text")){ - assertEquals(18, rt.getFontSize()); + assertEquals(18, rt.getFontSize(), 0); } } } @@ -160,7 +147,7 @@ public final class TestShapes { // Create a new textbox, and give it lots of properties HSLFTextBox txtbox = new HSLFTextBox(); - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); txtbox.setText(val); rt.setFontName("Arial"); rt.setFontSize(42); @@ -171,13 +158,13 @@ public final class TestShapes { sl.addShape(txtbox); // Check it before save - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; - assertEquals(val, rt.getText()); - assertEquals(42, rt.getFontSize()); + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); + assertEquals(val, rt.getRawText()); + assertEquals(42, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); assertFalse(rt.isUnderlined()); - assertEquals("Arial", rt.getFontName()); + assertEquals("Arial", rt.getFontFamily()); assertEquals(Color.red, rt.getFontColor()); // Serialize and read again @@ -186,18 +173,18 @@ public final class TestShapes { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - sl = ppt.getSlides()[0]; + sl = ppt.getSlides().get(0); - txtbox = (HSLFTextBox)sl.getShapes()[0]; - rt = txtbox.getTextParagraph().getRichTextRuns()[0]; + txtbox = (HSLFTextBox)sl.getShapes().get(0); + rt = txtbox.getTextParagraphs().get(0).getTextRuns().get(0); // Check after save - assertEquals(val, rt.getText()); - assertEquals(42, rt.getFontSize()); + assertEquals(val, rt.getRawText()); + assertEquals(42, rt.getFontSize(), 0); assertTrue(rt.isBold()); assertTrue(rt.isItalic()); assertFalse(rt.isUnderlined()); - assertEquals("Arial", rt.getFontName()); + assertEquals("Arial", rt.getFontFamily()); assertEquals(Color.red, rt.getFontColor()); } @@ -206,13 +193,13 @@ public final class TestShapes { */ @Test public void emptyTextBox() { - assertEquals(2, pptB.getSlides().length); - HSLFSlide s1 = pptB.getSlides()[0]; - HSLFSlide s2 = pptB.getSlides()[1]; + assertEquals(2, pptB.getSlides().size()); + HSLFSlide s1 = pptB.getSlides().get(0); + HSLFSlide s2 = pptB.getSlides().get(1); // Check we can get the shapes count - assertEquals(2, s1.getShapes().length); - assertEquals(2, s2.getShapes().length); + assertEquals(2, s1.getShapes().size()); + assertEquals(2, s2.getShapes().size()); } /** @@ -231,19 +218,20 @@ public final class TestShapes { private void textBoxSet(String filename) throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream(filename)); - HSLFSlide[] sl = ppt.getSlides(); - for (int k = 0; k < sl.length; k++) { + for (HSLFSlide sld : ppt.getSlides()) { ArrayList lst1 = new ArrayList(); - HSLFTextParagraph[] txt = sl[k].getTextRuns(); - for (int i = 0; i < txt.length; i++) { - lst1.add(txt[i].getText()); + for (List txt : sld.getTextParagraphs()) { + for (HSLFTextParagraph p : txt) { + for (HSLFTextRun r : p) { + lst1.add(r.getRawText()); + } + } } ArrayList lst2 = new ArrayList(); - HSLFShape[] sh = sl[k].getShapes(); - for (int i = 0; i < sh.length; i++) { - if (sh[i] instanceof HSLFTextShape){ - HSLFTextShape tbox = (HSLFTextShape)sh[i]; + for (HSLFShape sh : sld.getShapes()) { + if (sh instanceof HSLFTextShape){ + HSLFTextShape tbox = (HSLFTextShape)sh; lst2.add(tbox.getText()); } } @@ -285,22 +273,22 @@ public final class TestShapes { ppt = new HSLFSlideShow(is); is.close(); - slide = ppt.getSlides()[0]; + slide = ppt.getSlides().get(0); - HSLFShape[] shape = slide.getShapes(); - assertEquals(1, shape.length); - assertTrue(shape[0] instanceof HSLFGroupShape); + List shape = slide.getShapes(); + assertEquals(1, shape.size()); + assertTrue(shape.get(0) instanceof HSLFGroupShape); - group = (HSLFGroupShape)shape[0]; - HSLFShape[] grshape = group.getShapes(); - assertEquals(2, grshape.length); - assertTrue(grshape[0] instanceof HSLFPictureShape); - assertTrue(grshape[1] instanceof Line); + group = (HSLFGroupShape)shape.get(0); + List grshape = group.getShapes(); + assertEquals(2, grshape.size()); + assertTrue(grshape.get(0) instanceof HSLFPictureShape); + assertTrue(grshape.get(1) instanceof Line); - pict = (HSLFPictureShape)grshape[0]; + pict = (HSLFPictureShape)grshape.get(0); assertEquals(new Rectangle(0, 0, 200, 200), pict.getAnchor()); - line = (Line)grshape[1]; + line = (Line)grshape.get(1); assertEquals(new Rectangle(300, 300, 500, 0), line.getAnchor()); } @@ -311,16 +299,16 @@ public final class TestShapes { public void removeShapes() throws IOException { String file = "with_textbox.ppt"; HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream(file)); - HSLFSlide sl = ppt.getSlides()[0]; - HSLFShape[] sh = sl.getShapes(); - assertEquals("expected four shaped in " + file, 4, sh.length); + HSLFSlide sl = ppt.getSlides().get(0); + List sh = sl.getShapes(); + assertEquals("expected four shaped in " + file, 4, sh.size()); //remove all - for (int i = 0; i < sh.length; i++) { - boolean ok = sl.removeShape(sh[i]); + for (int i = 0; i < sh.size(); i++) { + boolean ok = sl.removeShape(sh.get(i)); assertTrue("Failed to delete shape #" + i, ok); } //now Slide.getShapes() should return an empty array - assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length); + assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().size()); //serialize and read again. The file should be readable and contain no shapes ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -328,8 +316,8 @@ public final class TestShapes { out.close(); ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); - sl = ppt.getSlides()[0]; - assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().length); + sl = ppt.getSlides().get(0); + assertEquals("expected 0 shaped in " + file, 0, sl.getShapes().size()); } @Test @@ -400,24 +388,24 @@ public final class TestShapes { @Test public void lineColor() throws IOException { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("51731.ppt")); - HSLFShape[] shape = ppt.getSlides()[0].getShapes(); + List shape = ppt.getSlides().get(0).getShapes(); - assertEquals(4, shape.length); + assertEquals(4, shape.size()); - HSLFTextShape sh1 = (HSLFTextShape)shape[0]; + HSLFTextShape sh1 = (HSLFTextShape)shape.get(0); assertEquals("Hello Apache POI", sh1.getText()); assertNull(sh1.getLineColor()); - HSLFTextShape sh2 = (HSLFTextShape)shape[1]; + HSLFTextShape sh2 = (HSLFTextShape)shape.get(1); assertEquals("Why are you showing this border?", sh2.getText()); assertNull(sh2.getLineColor()); - HSLFTextShape sh3 = (HSLFTextShape)shape[2]; + HSLFTextShape sh3 = (HSLFTextShape)shape.get(2); assertEquals("Text in a black border", sh3.getText()); assertEquals(Color.black, sh3.getLineColor()); assertEquals(0.75, sh3.getLineWidth(), 0); - HSLFTextShape sh4 = (HSLFTextShape)shape[3]; + HSLFTextShape sh4 = (HSLFTextShape)shape.get(3); assertEquals("Border width is 5 pt", sh4.getText()); assertEquals(Color.black, sh4.getLineColor()); assertEquals(5.0, sh4.getLineWidth(), 0); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSheet.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSheet.java index 60b8ca42e2..330c832486 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSheet.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSheet.java @@ -17,14 +17,17 @@ package org.apache.poi.hslf.model; -import junit.framework.AssertionFailedError; -import junit.framework.TestCase; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.util.List; + +import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException; import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.hslf.record.PPDrawing; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test common functionality of the Sheet object. @@ -32,12 +35,13 @@ import org.apache.poi.POIDataSamples; * * @author Yegor Kozlov */ -public final class TestSheet extends TestCase { +public final class TestSheet { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); /** * For each ppt in the test directory check that all sheets are properly initialized */ + @Test public void testSheet() throws Exception { String[] tests = {"SampleShow.ppt", "backgrounds.ppt", "text_shapes.ppt", "pictures.ppt"}; for (String file : tests) { @@ -51,14 +55,13 @@ public final class TestSheet extends TestCase { } private void doSlideShow(HSLFSlideShow ppt) { - HSLFSlide[] slide = ppt.getSlides(); - for (int i = 0; i < slide.length; i++) { - verify(slide[i]); + for (HSLFSlide slide : ppt.getSlides()) { + verify(slide); - HSLFNotes notes = slide[i].getNotesSheet(); + HSLFNotes notes = slide.getNotes(); if(notes != null) verify(notes); - HSLFMasterSheet master = slide[i].getMasterSheet(); + HSLFMasterSheet master = slide.getMasterSheet(); assertNotNull(master); verify(master); } @@ -79,23 +82,19 @@ public final class TestSheet extends TestCase { assertTrue(sheet._getSheetNumber() != 0); assertTrue(sheet._getSheetRefId() != 0); - HSLFTextParagraph[] txt = sheet.getTextRuns(); - if (txt == null) { - throw new AssertionFailedError("no text runs"); - } - for (int i = 0; i < txt.length; i++) { - assertNotNull(txt[i].getSheet()); + List txt = sheet.getTextParagraphs(); + assertTrue("no text runs", txt != null && !txt.isEmpty()); + for (HSLFTextParagraph t : txt) { + assertNotNull(t.getSheet()); } - HSLFShape[] shape = sheet.getShapes(); - if (shape == null) { - throw new AssertionFailedError("no shapes"); - } - for (int i = 0; i < shape.length; i++) { - assertNotNull(shape[i].getSpContainer()); - assertNotNull(shape[i].getSheet()); - assertNotNull(shape[i].getShapeName()); - assertNotNull(shape[i].getAnchor()); + List shape = sheet.getShapes(); + assertTrue("no shapes", shape != null && !shape.isEmpty()); + for (HSLFShape s : shape) { + assertNotNull(s.getSpContainer()); + assertNotNull(s.getSheet()); + assertNotNull(s.getShapeName()); + assertNotNull(s.getAnchor()); } } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideChangeNotes.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideChangeNotes.java index 2d4fe15131..57f6f5adb9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideChangeNotes.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideChangeNotes.java @@ -18,29 +18,33 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; -import org.apache.poi.hslf.record.SlideAtom; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.record.SlideAtom; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Before; +import org.junit.Test; /** * Tests that changing a slide's idea of what notes sheet is its works right * * @author Nick Burch (nick at torchbox dot com) */ -public final class TestSlideChangeNotes extends TestCase { +public final class TestSlideChangeNotes { // SlideShow primed on the test data private HSLFSlideShow ss; - public TestSlideChangeNotes() throws Exception { + @Before + public void init() throws Exception { POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); HSLFSlideShowImpl hss = new HSLFSlideShowImpl(_slTests.openResourceAsStream("basic_test_ppt_file.ppt")); ss = new HSLFSlideShow(hss); } + @Test public void testSetToNone() { - HSLFSlide slideOne = ss.getSlides()[0]; + HSLFSlide slideOne = ss.getSlides().get(0); SlideAtom sa = slideOne.getSlideRecord().getSlideAtom(); slideOne.setNotes(null); @@ -48,9 +52,10 @@ public final class TestSlideChangeNotes extends TestCase { assertEquals(0, sa.getNotesID()); } + @Test public void testSetToSomething() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFNotes notesOne = ss.getNotes()[1]; + HSLFSlide slideOne = ss.getSlides().get(0); + HSLFNotes notesOne = ss.getNotes().get(1); SlideAtom sa = slideOne.getSlideRecord().getSlideAtom(); slideOne.setNotes(notesOne); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideMaster.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideMaster.java index ffb6563da5..e6b24ce1b9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideMaster.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlideMaster.java @@ -17,63 +17,66 @@ package org.apache.poi.hslf.model; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.util.List; -import junit.framework.TestCase; - +import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; import org.apache.poi.hslf.record.Environment; import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Tests for SlideMaster * * @author Yegor Kozlov */ -public final class TestSlideMaster extends TestCase{ +public final class TestSlideMaster { private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); /** * The reference ppt has two masters. * Check we can read their attributes. */ + @Test public void testSlideMaster() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); Environment env = ppt.getDocumentRecord().getEnvironment(); - SlideMaster[] master = ppt.getSlidesMasters(); - assertEquals(2, master.length); + List master = ppt.getSlideMasters(); + assertEquals(2, master.size()); //character attributes - assertEquals(40, master[0].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.size", true).getValue()); - assertEquals(48, master[1].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.size", true).getValue()); + assertEquals(40, master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.size", true).getValue()); + assertEquals(48, master.get(1).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.size", true).getValue()); - int font1 = master[0].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue(); - int font2 = master[1].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue(); + int font1 = master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue(); + int font2 = master.get(1).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "font.index", true).getValue(); assertEquals("Arial", env.getFontCollection().getFontWithId(font1)); assertEquals("Georgia", env.getFontCollection().getFontWithId(font2)); - CharFlagsTextProp prop1 = (CharFlagsTextProp)master[0].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true); + CharFlagsTextProp prop1 = (CharFlagsTextProp)master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true); assertEquals(false, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX)); assertEquals(false, prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX)); assertEquals(true, prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX)); - CharFlagsTextProp prop2 = (CharFlagsTextProp)master[1].getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true); + CharFlagsTextProp prop2 = (CharFlagsTextProp)master.get(1).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true); assertEquals(false, prop2.getSubValue(CharFlagsTextProp.BOLD_IDX)); assertEquals(true, prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX)); assertEquals(false, prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX)); //now paragraph attributes - assertEquals(0x266B, master[0].getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.char", false).getValue()); - assertEquals(0x2022, master[1].getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.char", false).getValue()); + assertEquals(0x266B, master.get(0).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.char", false).getValue()); + assertEquals(0x2022, master.get(1).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.char", false).getValue()); - int b1 = master[0].getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue(); - int b2 = master[1].getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue(); + int b1 = master.get(0).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue(); + int b2 = master.get(1).getStyleAttribute(TextHeaderAtom.BODY_TYPE, 0, "bullet.font", false).getValue(); assertEquals("Arial", env.getFontCollection().getFontWithId(b1)); assertEquals("Georgia", env.getFontCollection().getFontWithId(b2)); } @@ -81,19 +84,20 @@ public final class TestSlideMaster extends TestCase{ /** * Test we can read default text attributes for a title master sheet */ + @Test public void testTitleMasterTextAttributes() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); - TitleMaster[] master = ppt.getTitleMasters(); - assertEquals(1, master.length); + List master = ppt.getTitleMasters(); + assertEquals(1, master.size()); - assertEquals(32, master[0].getStyleAttribute(TextHeaderAtom.CENTER_TITLE_TYPE, 0, "font.size", true).getValue()); - CharFlagsTextProp prop1 = (CharFlagsTextProp)master[0].getStyleAttribute(TextHeaderAtom.CENTER_TITLE_TYPE, 0, "char_flags", true); + assertEquals(32, master.get(0).getStyleAttribute(TextHeaderAtom.CENTER_TITLE_TYPE, 0, "font.size", true).getValue()); + CharFlagsTextProp prop1 = (CharFlagsTextProp)master.get(0).getStyleAttribute(TextHeaderAtom.CENTER_TITLE_TYPE, 0, "char_flags", true); assertEquals(true, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX)); assertEquals(false, prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX)); assertEquals(true, prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX)); - assertEquals(20, master[0].getStyleAttribute(TextHeaderAtom.CENTRE_BODY_TYPE, 0, "font.size", true).getValue()); - CharFlagsTextProp prop2 = (CharFlagsTextProp)master[0].getStyleAttribute(TextHeaderAtom.CENTRE_BODY_TYPE, 0, "char_flags", true); + assertEquals(20, master.get(0).getStyleAttribute(TextHeaderAtom.CENTRE_BODY_TYPE, 0, "font.size", true).getValue()); + CharFlagsTextProp prop2 = (CharFlagsTextProp)master.get(0).getStyleAttribute(TextHeaderAtom.CENTRE_BODY_TYPE, 0, "char_flags", true); assertEquals(true, prop2.getSubValue(CharFlagsTextProp.BOLD_IDX)); assertEquals(false, prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX)); assertEquals(false, prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX)); @@ -102,25 +106,26 @@ public final class TestSlideMaster extends TestCase{ /** * Slide 3 has title layout and follows the TitleMaster. Verify that. */ + @Test public void testTitleMaster() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); - HSLFSlide slide = ppt.getSlides()[2]; + HSLFSlide slide = ppt.getSlides().get(2); HSLFMasterSheet masterSheet = slide.getMasterSheet(); - assertTrue(masterSheet instanceof TitleMaster); + assertTrue(masterSheet instanceof HSLFTitleMaster); - HSLFTextParagraph[] txt = slide.getTextRuns(); - for (int i = 0; i < txt.length; i++) { - HSLFTextRun rt = txt[i].getRichTextRuns()[0]; - switch(txt[i].getRunType()){ + List txt = slide.getTextParagraphs(); + for (int i = 0; i < txt.size(); i++) { + HSLFTextRun rt = txt.get(i).getTextRuns().get(0); + switch(txt.get(i).getRunType()){ case TextHeaderAtom.CENTER_TITLE_TYPE: - assertEquals("Arial", rt.getFontName()); - assertEquals(32, rt.getFontSize()); + assertEquals("Arial", rt.getFontFamily()); + assertEquals(32, rt.getFontSize(), 0); assertEquals(true, rt.isBold()); assertEquals(true, rt.isUnderlined()); break; case TextHeaderAtom.CENTRE_BODY_TYPE: - assertEquals("Courier New", rt.getFontName()); - assertEquals(20, rt.getFontSize()); + assertEquals("Courier New", rt.getFontFamily()); + assertEquals(20, rt.getFontSize(), 0); assertEquals(true, rt.isBold()); assertEquals(false, rt.isUnderlined()); break; @@ -131,47 +136,44 @@ public final class TestSlideMaster extends TestCase{ /** * If a style attribute is not set ensure it is read from the master */ + @Test public void testMasterAttributes() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); - HSLFSlide[] slide = ppt.getSlides(); - assertEquals(3, slide.length); - HSLFTextParagraph[] trun; - - trun = slide[0].getTextRuns(); - for (int i = 0; i < trun.length; i++) { - if (trun[i].getRunType() == TextHeaderAtom.TITLE_TYPE){ - HSLFTextRun rt = trun[i].getRichTextRuns()[0]; - assertEquals(40, rt.getFontSize()); + List slide = ppt.getSlides(); + assertEquals(3, slide.size()); + for (HSLFTextParagraph trun : slide.get(0).getTextParagraphs()) { + if (trun.getRunType() == TextHeaderAtom.TITLE_TYPE){ + HSLFTextRun rt = trun.getTextRuns().get(0); + assertEquals(40, rt.getFontSize(), 0); assertEquals(true, rt.isUnderlined()); - assertEquals("Arial", rt.getFontName()); - } else if (trun[i].getRunType() == TextHeaderAtom.BODY_TYPE){ - HSLFTextRun rt; - rt = trun[i].getRichTextRuns()[0]; - assertEquals(0, rt.getIndentLevel()); - assertEquals(32, rt.getFontSize()); - assertEquals("Arial", rt.getFontName()); - - rt = trun[i].getRichTextRuns()[1]; - assertEquals(1, rt.getIndentLevel()); - assertEquals(28, rt.getFontSize()); - assertEquals("Arial", rt.getFontName()); + assertEquals("Arial", rt.getFontFamily()); + } else if (trun.getRunType() == TextHeaderAtom.BODY_TYPE){ + HSLFTextRun rt = trun.getTextRuns().get(0); + assertEquals(0, trun.getIndentLevel()); + assertEquals(32, rt.getFontSize(), 0); + assertEquals("Arial", rt.getFontFamily()); + + rt = trun.getTextRuns().get(1); + assertEquals(1, trun.getIndentLevel()); + assertEquals(28, rt.getFontSize(), 0); + assertEquals("Arial", rt.getFontFamily()); } } - trun = slide[1].getTextRuns(); - for (int i = 0; i < trun.length; i++) { - if (trun[i].getRunType() == TextHeaderAtom.TITLE_TYPE){ - HSLFTextRun rt = trun[i].getRichTextRuns()[0]; - assertEquals(48, rt.getFontSize()); + ; + for (HSLFTextParagraph trun : slide.get(1).getTextParagraphs()) { + if (trun.getRunType() == TextHeaderAtom.TITLE_TYPE){ + HSLFTextRun rt = trun.getTextRuns().get(0); + assertEquals(48, rt.getFontSize(), 0); assertEquals(true, rt.isItalic()); - assertEquals("Georgia", rt.getFontName()); - } else if (trun[i].getRunType() == TextHeaderAtom.BODY_TYPE){ + assertEquals("Georgia", rt.getFontFamily()); + } else if (trun.getRunType() == TextHeaderAtom.BODY_TYPE){ HSLFTextRun rt; - rt = trun[i].getRichTextRuns()[0]; - assertEquals(0, rt.getIndentLevel()); - assertEquals(32, rt.getFontSize()); - assertEquals("Courier New", rt.getFontName()); + rt = trun.getTextRuns().get(0); + assertEquals(0, trun.getIndentLevel()); + assertEquals(32, rt.getFontSize(), 0); + assertEquals("Courier New", rt.getFontFamily()); } } @@ -180,20 +182,21 @@ public final class TestSlideMaster extends TestCase{ /** * Check we can dynamically assign a slide master to a slide. */ + @Test public void testChangeSlideMaster() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); - SlideMaster[] master = ppt.getSlidesMasters(); - HSLFSlide[] slide = ppt.getSlides(); + List master = ppt.getSlideMasters(); + List slide = ppt.getSlides(); int sheetNo; //each slide uses its own master - assertEquals(slide[0].getMasterSheet()._getSheetNumber(), master[0]._getSheetNumber()); - assertEquals(slide[1].getMasterSheet()._getSheetNumber(), master[1]._getSheetNumber()); + assertEquals(slide.get(0).getMasterSheet()._getSheetNumber(), master.get(0)._getSheetNumber()); + assertEquals(slide.get(1).getMasterSheet()._getSheetNumber(), master.get(1)._getSheetNumber()); //all slides use the first master slide - sheetNo = master[0]._getSheetNumber(); - for (int i = 0; i < slide.length; i++) { - slide[i].setMasterSheet(master[0]); + sheetNo = master.get(0)._getSheetNumber(); + for (HSLFSlide s : slide) { + s.setMasterSheet(master.get(0)); } ByteArrayOutputStream out; @@ -203,10 +206,10 @@ public final class TestSlideMaster extends TestCase{ out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - master = ppt.getSlidesMasters(); + master = ppt.getSlideMasters(); slide = ppt.getSlides(); - for (int i = 0; i < slide.length; i++) { - assertEquals(sheetNo, slide[i].getMasterSheet()._getSheetNumber()); + for (HSLFSlide s : slide) { + assertEquals(sheetNo, s.getMasterSheet()._getSheetNumber()); } } @@ -214,33 +217,22 @@ public final class TestSlideMaster extends TestCase{ * Varify we can read attrubutes for different identtation levels. * (typical for the "bullted body" placeholder) */ + @Test public void testIndentation() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt")); - HSLFSlide slide = ppt.getSlides()[0]; - HSLFTextParagraph[] trun; - - trun = slide.getTextRuns(); - for (int i = 0; i < trun.length; i++) { - if (trun[i].getRunType() == TextHeaderAtom.TITLE_TYPE){ - HSLFTextRun rt = trun[i].getRichTextRuns()[0]; - assertEquals(40, rt.getFontSize()); + HSLFSlide slide = ppt.getSlides().get(0); + + for (HSLFTextParagraph trun : slide.getTextParagraphs()) { + if (trun.getRunType() == TextHeaderAtom.TITLE_TYPE){ + HSLFTextRun rt = trun.getTextRuns().get(0); + assertEquals(40, rt.getFontSize(), 0); assertEquals(true, rt.isUnderlined()); - assertEquals("Arial", rt.getFontName()); - } else if (trun[i].getRunType() == TextHeaderAtom.BODY_TYPE){ - HSLFTextRun[] rt = trun[i].getRichTextRuns(); - for (int j = 0; j < rt.length; j++) { - int indent = rt[j].getIndentLevel(); - switch (indent){ - case 0: - assertEquals(32, rt[j].getFontSize()); - break; - case 1: - assertEquals(28, rt[j].getFontSize()); - break; - case 2: - assertEquals(24, rt[j].getFontSize()); - break; - } + assertEquals("Arial", rt.getFontFamily()); + } else if (trun.getRunType() == TextHeaderAtom.BODY_TYPE){ + int indents[] = { 32, 28, 24 }; + for (HSLFTextRun rt : trun.getTextRuns()) { + int indent = trun.getIndentLevel(); + assertEquals(indents[indent], rt.getFontSize(), 0); } } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlides.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlides.java index f5e0abef59..a84caefd68 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlides.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestSlides.java @@ -17,13 +17,15 @@ package org.apache.poi.hslf.model; -import junit.framework.TestCase; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; - -import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; + +import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test adding new slides to a ppt. @@ -32,18 +34,19 @@ import java.io.ByteArrayInputStream; * stuff does * @author Yegor Kozlov */ -public final class TestSlides extends TestCase { +public final class TestSlides { /** * Add 1 slide to an empty ppt. * @throws Exception */ + @Test public void testAddSlides1() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(new HSLFSlideShowImpl( TestSlides.class.getResourceAsStream("/org/apache/poi/hslf/data/empty.ppt") )); - assertTrue(ppt.getSlides().length == 0); + assertTrue(ppt.getSlides().isEmpty()); HSLFSlide s1 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 1); + assertEquals(1, ppt.getSlides().size()); assertEquals(3, s1._getSheetRefId()); assertEquals(256, s1._getSheetNumber()); assertEquals(1, s1.getSlideNumber()); @@ -54,60 +57,62 @@ public final class TestSlides extends TestCase { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertTrue(ppt.getSlides().length == 1); + assertEquals(1, ppt.getSlides().size()); } /** * Add 2 slides to an empty ppt * @throws Exception */ + @Test public void testAddSlides2() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(new HSLFSlideShowImpl( TestSlides.class.getResourceAsStream("/org/apache/poi/hslf/data/empty.ppt") )); - assertTrue(ppt.getSlides().length == 0); + assertTrue(ppt.getSlides().isEmpty()); HSLFSlide s1 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 1); + assertEquals(1, ppt.getSlides().size()); assertEquals(3, s1._getSheetRefId()); assertEquals(256, s1._getSheetNumber()); assertEquals(1, s1.getSlideNumber()); HSLFSlide s2 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 2); + assertEquals(2, ppt.getSlides().size()); assertEquals(4, s2._getSheetRefId()); assertEquals(257, s2._getSheetNumber()); assertEquals(2, s2.getSlideNumber()); //serialize and read again - ByteArrayOutputStream out = new ByteArrayOutputStream(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); ppt.write(out); out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertTrue(ppt.getSlides().length == 2); + assertEquals(2, ppt.getSlides().size()); } /** * Add 3 slides to an empty ppt * @throws Exception */ + @Test public void testAddSlides3() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(new HSLFSlideShowImpl( TestSlides.class.getResourceAsStream("/org/apache/poi/hslf/data/empty.ppt") )); - assertTrue(ppt.getSlides().length == 0); + assertTrue(ppt.getSlides().isEmpty()); HSLFSlide s1 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 1); + assertEquals(1, ppt.getSlides().size()); assertEquals(3, s1._getSheetRefId()); assertEquals(256, s1._getSheetNumber()); assertEquals(1, s1.getSlideNumber()); HSLFSlide s2 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 2); + assertEquals(2, ppt.getSlides().size()); assertEquals(4, s2._getSheetRefId()); assertEquals(257, s2._getSheetNumber()); assertEquals(2, s2.getSlideNumber()); HSLFSlide s3 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 3); + assertEquals(3, ppt.getSlides().size()); assertEquals(5, s3._getSheetRefId()); assertEquals(258, s3._getSheetNumber()); assertEquals(3, s3.getSlideNumber()); @@ -119,17 +124,17 @@ public final class TestSlides extends TestCase { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertTrue(ppt.getSlides().length == 3); + assertEquals(3, ppt.getSlides().size()); // Check IDs are still right - s1 = ppt.getSlides()[0]; + s1 = ppt.getSlides().get(0); assertEquals(256, s1._getSheetNumber()); assertEquals(3, s1._getSheetRefId()); - s2 = ppt.getSlides()[1]; + s2 = ppt.getSlides().get(1); assertEquals(257, s2._getSheetNumber()); assertEquals(4, s2._getSheetRefId()); - s3 = ppt.getSlides()[2];; - assertTrue(ppt.getSlides().length == 3); + s3 = ppt.getSlides().get(2);; + assertEquals(3, ppt.getSlides().size()); assertEquals(258, s3._getSheetNumber()); assertEquals(5, s3._getSheetRefId()); } @@ -137,25 +142,26 @@ public final class TestSlides extends TestCase { /** * Add slides to ppt which already has two slides */ + @Test public void testAddSlides2to3() throws Exception { POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); HSLFSlideShow ppt = new HSLFSlideShow(slTests.openResourceAsStream("basic_test_ppt_file.ppt")); - assertTrue(ppt.getSlides().length == 2); + assertEquals(2, ppt.getSlides().size()); // First slide is 256 / 4 - HSLFSlide s1 = ppt.getSlides()[0]; + HSLFSlide s1 = ppt.getSlides().get(0); assertEquals(256, s1._getSheetNumber()); assertEquals(4, s1._getSheetRefId()); // Last slide is 257 / 6 - HSLFSlide s2 = ppt.getSlides()[1]; + HSLFSlide s2 = ppt.getSlides().get(1); assertEquals(257, s2._getSheetNumber()); assertEquals(6, s2._getSheetRefId()); // Add another slide, goes in at the end HSLFSlide s3 = ppt.createSlide(); - assertTrue(ppt.getSlides().length == 3); + assertEquals(3, ppt.getSlides().size()); assertEquals(258, s3._getSheetNumber()); assertEquals(8, s3._getSheetRefId()); @@ -166,18 +172,18 @@ public final class TestSlides extends TestCase { out.close(); ppt = new HSLFSlideShow(new HSLFSlideShowImpl(new ByteArrayInputStream(out.toByteArray()))); - assertTrue(ppt.getSlides().length == 3); + assertEquals(3, ppt.getSlides().size()); // Check IDs are still right - s1 = ppt.getSlides()[0]; + s1 = ppt.getSlides().get(0); assertEquals(256, s1._getSheetNumber()); assertEquals(4, s1._getSheetRefId()); - s2 = ppt.getSlides()[1]; + s2 = ppt.getSlides().get(1); assertEquals(257, s2._getSheetNumber()); assertEquals(6, s2._getSheetRefId()); - s3 = ppt.getSlides()[2];; - assertTrue(ppt.getSlides().length == 3); + s3 = ppt.getSlides().get(2); + assertEquals(3, ppt.getSlides().size()); assertEquals(258, s3._getSheetNumber()); assertEquals(8, s3._getSheetRefId()); } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java index d3fb354063..0c5fcb69bb 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTable.java @@ -17,24 +17,27 @@ package org.apache.poi.hslf.model; +import static org.junit.Assert.*; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; - -import junit.framework.TestCase; +import java.util.List; import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; +import org.junit.Test; /** * Test Table object. * * @author Yegor Kozlov */ -public final class TestTable extends TestCase { +public final class TestTable { /** * Test that ShapeFactory works properly and returns Table */ + @Test public void testShapeFactory() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(); @@ -45,10 +48,10 @@ public final class TestTable extends TestCase { TableCell cell = tbl.getCell(0, 0); //table cells have type=TextHeaderAtom.OTHER_TYPE, see bug #46033 - assertEquals(TextHeaderAtom.OTHER_TYPE, cell.getTextParagraph().getRunType()); + assertEquals(TextHeaderAtom.OTHER_TYPE, cell.getTextParagraphs().get(0).getRunType()); - assertTrue(slide.getShapes()[0] instanceof Table); - Table tbl2 = (Table)slide.getShapes()[0]; + assertTrue(slide.getShapes().get(0) instanceof Table); + Table tbl2 = (Table)slide.getShapes().get(0); assertEquals(tbl.getNumberOfColumns(), tbl2.getNumberOfColumns()); assertEquals(tbl.getNumberOfRows(), tbl2.getNumberOfRows()); @@ -57,9 +60,9 @@ public final class TestTable extends TestCase { out.close(); ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); - slide = ppt.getSlides()[0]; - assertTrue(slide.getShapes()[0] instanceof Table); - Table tbl3 = (Table)slide.getShapes()[0]; + slide = ppt.getSlides().get(0); + assertTrue(slide.getShapes().get(0) instanceof Table); + Table tbl3 = (Table)slide.getShapes().get(0); assertEquals(tbl.getNumberOfColumns(), tbl3.getNumberOfColumns()); assertEquals(tbl.getNumberOfRows(), tbl3.getNumberOfRows()); } @@ -67,25 +70,27 @@ public final class TestTable extends TestCase { /** * Error constructing Table when rownum=1 */ + @Test public void test45889(){ HSLFSlideShow ppt = new HSLFSlideShow(); HSLFSlide slide = ppt.createSlide(); - HSLFShape[] shapes; + List shapes; Table tbl1 = new Table(1, 5); assertEquals(5, tbl1.getNumberOfColumns()); assertEquals(1, tbl1.getNumberOfRows()); slide.addShape(tbl1); shapes = slide.getShapes(); - assertEquals(1, shapes.length); + assertEquals(1, shapes.size()); - Table tbl2 = (Table)shapes[0]; + Table tbl2 = (Table)shapes.get(0); assertSame(tbl1.getSpContainer(), tbl2.getSpContainer()); assertEquals(tbl1.getNumberOfColumns(), tbl2.getNumberOfColumns()); assertEquals(tbl1.getNumberOfRows(), tbl2.getNumberOfRows()); } + @Test public void testIllegalCOnstruction(){ try { new Table(0, 5); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRun.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRun.java deleted file mode 100644 index 01ce6a0534..0000000000 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRun.java +++ /dev/null @@ -1,551 +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 java.awt.*; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; - -import junit.framework.TestCase; - -import org.apache.poi.hslf.model.textproperties.TextPropCollection; -import org.apache.poi.hslf.record.Record; -import org.apache.poi.hslf.record.TextBytesAtom; -import org.apache.poi.hslf.record.TextCharsAtom; -import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.POIDataSamples; - -/** - * Tests for TextRuns - * - * @author Nick Burch (nick at torchbox dot com) - */ -public final class TestTextRun extends TestCase { - private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance(); - - // SlideShow primed on the test data - private HSLFSlideShow ss; - private HSLFSlideShow ssRich; - - protected void setUp() throws IOException { - - // Basic (non rich) test file - ss = new HSLFSlideShow(_slTests.openResourceAsStream("basic_test_ppt_file.ppt")); - - // Rich test file - ssRich = new HSLFSlideShow(_slTests.openResourceAsStream("Single_Coloured_Page.ppt")); - } - - /** - * Test to ensure that getting the text works correctly - */ - public void testGetText() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - - assertEquals(2, textRuns.length); - - // Get text works with \n - assertEquals("This is a test title", textRuns[0].getText()); - assertEquals("This is a test subtitle\nThis is on page 1", textRuns[1].getText()); - - // Raw text has \r instead - assertEquals("This is a test title", textRuns[0].getRawText()); - assertEquals("This is a test subtitle\rThis is on page 1", textRuns[1].getRawText()); - - - // Now check on a rich text run - HSLFSlide slideOneR = ssRich.getSlides()[0]; - HSLFTextParagraph[] textRunsR = slideOneR.getTextRuns(); - - assertEquals(2, textRunsR.length); - assertEquals("This is a title, it\u2019s in black", textRunsR[0].getText()); - assertEquals("This is the subtitle, in bold\nThis bit is blue and italic\nThis bit is red (normal)", textRunsR[1].getText()); - assertEquals("This is a title, it\u2019s in black", textRunsR[0].getRawText()); - assertEquals("This is the subtitle, in bold\rThis bit is blue and italic\rThis bit is red (normal)", textRunsR[1].getRawText()); - } - - /** - * Test to ensure changing non rich text bytes->bytes works correctly - */ - public void testSetText() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - HSLFTextParagraph run = textRuns[0]; - - // Check current text - assertEquals("This is a test title", run.getText()); - - // Change - String changeTo = "New test title"; - run.setText(changeTo); - assertEquals(changeTo, run.getText()); - - // Ensure trailing \n's are NOT stripped, it is legal to set a text with a trailing '\r' - run.setText(changeTo + "\n"); - assertEquals(changeTo + "\n", run.getText()); - } - - /** - * Test to ensure that changing non rich text between bytes and - * chars works correctly - */ - public void testAdvancedSetText() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph run = slideOne.getTextRuns()[0]; - - TextHeaderAtom tha = run._headerAtom; - TextBytesAtom tba = run._byteAtom; - TextCharsAtom tca = run._charAtom; - - // Bytes -> Bytes - assertNull(tca); - assertNotNull(tba); - assertFalse(run._isUnicode); - assertEquals("This is a test title", run.getText()); - - String changeBytesOnly = "New Test Title"; - run.setText(changeBytesOnly); - tba = run._byteAtom; - tca = run._charAtom; - - assertEquals(changeBytesOnly, run.getText()); - assertFalse(run._isUnicode); - assertNull(tca); - assertNotNull(tba); - - // Bytes -> Chars - assertNull(tca); - assertNotNull(tba); - assertFalse(run._isUnicode); - assertEquals(changeBytesOnly, run.getText()); - - String changeByteChar = "This is a test title with a '\u0121' g with a dot"; - run.setText(changeByteChar); - tba = run._byteAtom; - tca = run._charAtom; - - assertEquals(changeByteChar, run.getText()); - assertTrue(run._isUnicode); - assertNotNull(tca); - assertNull(tba); - - // Chars -> Chars - assertNull(tba); - assertNotNull(tca); - assertTrue(run._isUnicode); - assertEquals(changeByteChar, run.getText()); - - String changeCharChar = "This is a test title with a '\u0147' N with a hat"; - run.setText(changeCharChar); - tba = run._byteAtom; - tca = run._charAtom; - - assertEquals(changeCharChar, run.getText()); - assertTrue(run._isUnicode); - assertNotNull(tca); - assertNull(tba); - } - - /** - * Tests to ensure that non rich text has the right default rich text run - * set up for it - */ - public void testGetRichTextNonRich() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - - assertEquals(2, textRuns.length); - - HSLFTextParagraph trA = textRuns[0]; - HSLFTextParagraph trB = textRuns[1]; - - assertEquals(1, trA.getRichTextRuns().length); - assertEquals(1, trB.getRichTextRuns().length); - - HSLFTextRun rtrA = trA.getRichTextRuns()[0]; - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - - assertEquals(trA.getText(), rtrA.getText()); - assertEquals(trB.getText(), rtrB.getText()); - - assertNull(rtrA._getRawCharacterStyle()); - assertNull(rtrA._getRawParagraphStyle()); - assertNull(rtrB._getRawCharacterStyle()); - assertNull(rtrB._getRawParagraphStyle()); - } - - /** - * Tests to ensure that the rich text runs are built up correctly - */ - public void testGetRichText() { - HSLFSlide slideOne = ssRich.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - - assertEquals(2, textRuns.length); - - HSLFTextParagraph trA = textRuns[0]; - HSLFTextParagraph trB = textRuns[1]; - - assertEquals(1, trA.getRichTextRuns().length); - assertEquals(3, trB.getRichTextRuns().length); - - HSLFTextRun rtrA = trA.getRichTextRuns()[0]; - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - HSLFTextRun rtrC = trB.getRichTextRuns()[1]; - HSLFTextRun rtrD = trB.getRichTextRuns()[2]; - - assertEquals(trA.getText(), rtrA.getText()); - - assertEquals(trB.getText().substring(0, 30), rtrB.getText()); - assertEquals(trB.getText().substring(30,58), rtrC.getText()); - assertEquals(trB.getText().substring(58,82), rtrD.getText()); - - assertNull(rtrA._getRawCharacterStyle()); - assertNull(rtrA._getRawParagraphStyle()); - assertNotNull(rtrB._getRawCharacterStyle()); - assertNotNull(rtrB._getRawParagraphStyle()); - assertNotNull(rtrC._getRawCharacterStyle()); - assertNotNull(rtrC._getRawParagraphStyle()); - assertNotNull(rtrD._getRawCharacterStyle()); - assertNotNull(rtrD._getRawParagraphStyle()); - - // Same paragraph styles - assertEquals(rtrB._getRawParagraphStyle(), rtrC._getRawParagraphStyle()); - assertEquals(rtrB._getRawParagraphStyle(), rtrD._getRawParagraphStyle()); - - // Different char styles - assertFalse( rtrB._getRawCharacterStyle().equals( rtrC._getRawCharacterStyle() )); - assertFalse( rtrB._getRawCharacterStyle().equals( rtrD._getRawCharacterStyle() )); - assertFalse( rtrC._getRawCharacterStyle().equals( rtrD._getRawCharacterStyle() )); - } - - /** - * Tests to ensure that setting the text where the text isn't rich, - * ensuring that everything stays with the same default styling - */ - public void testSetTextWhereNotRich() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - HSLFTextParagraph trB = textRuns[1]; - assertEquals(1, trB.getRichTextRuns().length); - - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - assertEquals(trB.getText(), rtrB.getText()); - assertNull(rtrB._getRawCharacterStyle()); - assertNull(rtrB._getRawParagraphStyle()); - - // Change text via normal - trB.setText("Test Foo Test"); - rtrB = trB.getRichTextRuns()[0]; - assertEquals("Test Foo Test", trB.getText()); - assertEquals("Test Foo Test", rtrB.getText()); - assertNull(rtrB._getRawCharacterStyle()); - assertNull(rtrB._getRawParagraphStyle()); - } - - /** - * Tests to ensure that setting the text where the text is rich - * sets everything to the same styling - */ - public void testSetTextWhereRich() { - HSLFSlide slideOne = ssRich.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - HSLFTextParagraph trB = textRuns[1]; - assertEquals(3, trB.getRichTextRuns().length); - - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - HSLFTextRun rtrC = trB.getRichTextRuns()[1]; - HSLFTextRun rtrD = trB.getRichTextRuns()[2]; - TextPropCollection tpBP = rtrB._getRawParagraphStyle(); - TextPropCollection tpBC = rtrB._getRawCharacterStyle(); - TextPropCollection tpCP = rtrC._getRawParagraphStyle(); - TextPropCollection tpCC = rtrC._getRawCharacterStyle(); - TextPropCollection tpDP = rtrD._getRawParagraphStyle(); - TextPropCollection tpDC = rtrD._getRawCharacterStyle(); - - assertEquals(trB.getText().substring(0, 30), rtrB.getText()); - assertNotNull(tpBP); - assertNotNull(tpBC); - assertNotNull(tpCP); - assertNotNull(tpCC); - assertNotNull(tpDP); - assertNotNull(tpDC); - assertTrue(tpBP.equals(tpCP)); - assertTrue(tpBP.equals(tpDP)); - assertTrue(tpCP.equals(tpDP)); - assertFalse(tpBC.equals(tpCC)); - assertFalse(tpBC.equals(tpDC)); - assertFalse(tpCC.equals(tpDC)); - - // Change text via normal - trB.setText("Test Foo Test"); - - // Ensure now have first style - assertEquals(1, trB.getRichTextRuns().length); - rtrB = trB.getRichTextRuns()[0]; - assertEquals("Test Foo Test", trB.getText()); - assertEquals("Test Foo Test", rtrB.getText()); - assertNotNull(rtrB._getRawCharacterStyle()); - assertNotNull(rtrB._getRawParagraphStyle()); - assertEquals( tpBP, rtrB._getRawParagraphStyle() ); - assertEquals( tpBC, rtrB._getRawCharacterStyle() ); - } - - /** - * Test to ensure the right stuff happens if we change the text - * in a rich text run, that doesn't happen to actually be rich - */ - public void testChangeTextInRichTextRunNonRich() { - HSLFSlide slideOne = ss.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - HSLFTextParagraph trB = textRuns[1]; - assertEquals(1, trB.getRichTextRuns().length); - - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - assertEquals(trB.getText(), rtrB.getText()); - assertNull(rtrB._getRawCharacterStyle()); - assertNull(rtrB._getRawParagraphStyle()); - - // Change text via rich - rtrB.setText("Test Test Test"); - assertEquals("Test Test Test", trB.getText()); - assertEquals("Test Test Test", rtrB.getText()); - - // Will now have dummy props - assertNotNull(rtrB._getRawCharacterStyle()); - assertNotNull(rtrB._getRawParagraphStyle()); - } - - /** - * Tests to ensure changing the text within rich text runs works - * correctly - */ - public void testChangeTextInRichTextRun() { - HSLFSlide slideOne = ssRich.getSlides()[0]; - HSLFTextParagraph[] textRuns = slideOne.getTextRuns(); - HSLFTextParagraph trB = textRuns[1]; - assertEquals(3, trB.getRichTextRuns().length); - - // We start with 3 text runs, each with their own set of styles, - // but all sharing the same paragraph styles - HSLFTextRun rtrB = trB.getRichTextRuns()[0]; - HSLFTextRun rtrC = trB.getRichTextRuns()[1]; - HSLFTextRun rtrD = trB.getRichTextRuns()[2]; - TextPropCollection tpBP = rtrB._getRawParagraphStyle(); - TextPropCollection tpBC = rtrB._getRawCharacterStyle(); - TextPropCollection tpCP = rtrC._getRawParagraphStyle(); - TextPropCollection tpCC = rtrC._getRawCharacterStyle(); - TextPropCollection tpDP = rtrD._getRawParagraphStyle(); - TextPropCollection tpDC = rtrD._getRawCharacterStyle(); - - // Check text and stylings - assertEquals(trB.getText().substring(0, 30), rtrB.getText()); - assertNotNull(tpBP); - assertNotNull(tpBC); - assertNotNull(tpCP); - assertNotNull(tpCC); - assertNotNull(tpDP); - assertNotNull(tpDC); - assertTrue(tpBP.equals(tpCP)); - assertTrue(tpBP.equals(tpDP)); - assertTrue(tpCP.equals(tpDP)); - assertFalse(tpBC.equals(tpCC)); - assertFalse(tpBC.equals(tpDC)); - assertFalse(tpCC.equals(tpDC)); - - // Check text in the rich runs - assertEquals("This is the subtitle, in bold\n", rtrB.getText()); - assertEquals("This bit is blue and italic\n", rtrC.getText()); - assertEquals("This bit is red (normal)", rtrD.getText()); - - String newBText = "New Subtitle, will still be bold\n"; - String newCText = "New blue and italic text\n"; - String newDText = "Funky new normal red text"; - rtrB.setText(newBText); - rtrC.setText(newCText); - rtrD.setText(newDText); - assertEquals(newBText, rtrB.getText()); - assertEquals(newCText, rtrC.getText()); - assertEquals(newDText, rtrD.getText()); - - assertEquals(newBText + newCText + newDText, trB.getText()); - - // The styles should have been updated for the new sizes - assertEquals(newBText.length(), tpBC.getCharactersCovered()); - assertEquals(newCText.length(), tpCC.getCharactersCovered()); - assertEquals(newDText.length()+1, tpDC.getCharactersCovered()); // Last one is always one larger - - assertEquals( - newBText.length() + newCText.length() + newDText.length(), - tpBP.getCharactersCovered() - ); - - // Paragraph style should be sum of text length - assertEquals(newBText.length() + newCText.length() + newDText.length(), tpBP.getCharactersCovered()); - - // Check stylings still as expected - TextPropCollection ntpBC = rtrB._getRawCharacterStyle(); - TextPropCollection ntpCC = rtrC._getRawCharacterStyle(); - TextPropCollection ntpDC = rtrD._getRawCharacterStyle(); - assertEquals(tpBC.getTextPropList(), ntpBC.getTextPropList()); - assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList()); - assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList()); - } - - - /** - * Test case for Bug 41015. - * - * In some cases RichTextRun.getText() threw StringIndexOutOfBoundsException because - * of the wrong list of potential paragraph properties defined in StyleTextPropAtom. - * - */ - public void testBug41015() throws IOException { - HSLFTextRun[] rt; - - HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("bug-41015.ppt")); - HSLFSlide sl = ppt.getSlides()[0]; - HSLFTextParagraph[] txt = sl.getTextRuns(); - assertEquals(2, txt.length); - - rt = txt[0].getRichTextRuns(); - assertEquals(1, rt.length); - assertEquals(0, rt[0].getIndentLevel()); - assertEquals("sdfsdfsdf", rt[0].getText()); - - rt = txt[1].getRichTextRuns(); - assertEquals(2, rt.length); - assertEquals(0, rt[0].getIndentLevel()); - assertEquals("Sdfsdfsdf\n" + - "Dfgdfg\n" + - "Dfgdfgdfg\n", rt[0].getText()); - assertEquals(1, rt[1].getIndentLevel()); - assertEquals("Sdfsdfs\n" + - "Sdfsdf\n", rt[1].getText()); - } - - /** - * Test creation of TextRun objects. - */ - public void testAddTextRun() { - HSLFSlideShow ppt = new HSLFSlideShow(); - HSLFSlide slide = ppt.createSlide(); - - assertNull(slide.getTextRuns()); - - HSLFTextBox shape1 = new HSLFTextBox(); - HSLFTextParagraph run1 = shape1.getTextParagraph(); - assertSame(run1, shape1.createTextRun()); - run1.setText("Text 1"); - slide.addShape(shape1); - - //The array of Slide's text runs must be updated when new text shapes are added. - HSLFTextParagraph[] runs = slide.getTextRuns(); - assertNotNull(runs); - assertSame(run1, runs[0]); - - HSLFTextBox shape2 = new HSLFTextBox(); - HSLFTextParagraph run2 = shape2.getTextParagraph(); - assertSame(run2, shape2.createTextRun()); - run2.setText("Text 2"); - slide.addShape(shape2); - - runs = slide.getTextRuns(); - assertEquals(2, runs.length); - - assertSame(run1, runs[0]); - assertSame(run2, runs[1]); - - //as getShapes() - HSLFShape[] sh = slide.getShapes(); - assertEquals(2, sh.length); - assertTrue(sh[0] instanceof HSLFTextBox); - HSLFTextBox box1 = (HSLFTextBox)sh[0]; - assertSame(run1, box1.getTextParagraph()); - HSLFTextBox box2 = (HSLFTextBox)sh[1]; - assertSame(run2, box2.getTextParagraph()); - - //test Table - a complex group of shapes containing text objects - HSLFSlide slide2 = ppt.createSlide(); - assertNull(slide2.getTextRuns()); - Table table = new Table(2, 2); - slide2.addShape(table); - runs = slide2.getTextRuns(); - assertNotNull(runs); - assertEquals(4, runs.length); - } - - public void test48916() throws IOException { - HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("SampleShow.ppt")); - for(HSLFSlide slide : ppt.getSlides()){ - for(HSLFShape sh : slide.getShapes()){ - if(sh instanceof HSLFTextShape){ - HSLFTextShape tx = (HSLFTextShape)sh; - HSLFTextParagraph run = tx.getTextParagraph(); - //verify that records cached in TextRun and EscherTextboxWrapper are the same - Record[] runChildren = run.getRecords(); - Record[] txboxChildren = tx.getEscherTextboxWrapper().getChildRecords(); - assertEquals(runChildren.length, txboxChildren.length); - for(int i=0; i < txboxChildren.length; i++){ - assertSame(txboxChildren[i], runChildren[i]); - } - //caused NPE prior to fix of Bugzilla #48916 - run.getRichTextRuns()[0].setBold(true); - run.getRichTextRuns()[0].setFontColor(Color.RED); - } - } - } - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ppt.write(out); - ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); - for(HSLFSlide slide : ppt.getSlides()){ - for(HSLFShape sh : slide.getShapes()){ - if(sh instanceof HSLFTextShape){ - HSLFTextShape tx = (HSLFTextShape)sh; - HSLFTextParagraph run = tx.getTextParagraph(); - HSLFTextRun rt = run.getRichTextRuns()[0]; - assertTrue(rt.isBold()); - assertEquals(rt.getFontColor(), Color.RED); - } - } - } - - } - - public void test52244() throws IOException { - HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("52244.ppt")); - HSLFSlide slide = ppt.getSlides()[0]; - HSLFTextParagraph[] runs = slide.getTextRuns(); - - assertEquals("Arial", runs[0].getRichTextRuns()[0].getFontName()); - assertEquals(36, runs[0].getRichTextRuns()[0].getFontSize()); - - assertEquals("Arial", runs[1].getRichTextRuns()[0].getFontName()); - assertEquals(24, runs[1].getRichTextRuns()[0].getFontSize()); - - assertEquals("Arial", runs[2].getRichTextRuns()[0].getFontName()); - assertEquals(32, runs[2].getRichTextRuns()[0].getFontSize()); - - } - -} diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRunReWrite.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRunReWrite.java index c5a01341ae..8601f95ea5 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRunReWrite.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextRunReWrite.java @@ -17,15 +17,17 @@ package org.apache.poi.hslf.model; +import static org.junit.Assert.assertEquals; -import junit.framework.TestCase; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; -import java.io.*; - -import org.apache.poi.hslf.usermodel.HSLFTextRun; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; -import org.apache.poi.poifs.filesystem.*; import org.apache.poi.POIDataSamples; +import org.apache.poi.hslf.usermodel.*; +import org.apache.poi.poifs.filesystem.DocumentEntry; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.junit.Before; +import org.junit.Test; /** * Tests that if we load something up, get a TextRun, set the text @@ -34,7 +36,7 @@ import org.apache.poi.POIDataSamples; * * @author Nick Burch (nick at torchbox dot com) */ -public final class TestTextRunReWrite extends TestCase { +public final class TestTextRunReWrite { // HSLFSlideShow primed on the test data private HSLFSlideShowImpl hss; // HSLFSlideShow primed on the test data @@ -45,6 +47,7 @@ public final class TestTextRunReWrite extends TestCase { /** * Load up a test PPT file with rich data */ + @Before public void setUp() throws Exception { POIDataSamples slTests = POIDataSamples.getSlideShowInstance(); String filename = "Single_Coloured_Page_With_Fonts_and_Alignments.ppt"; @@ -53,35 +56,36 @@ public final class TestTextRunReWrite extends TestCase { ss = new HSLFSlideShow(hss); } - public void testWritesOutTheSameNonRich() throws Exception { + @Test + public void testWritesOutTheSameNonRich() throws Exception { // Grab the first text run on the first sheet - HSLFTextParagraph tr1 = ss.getSlides()[0].getTextRuns()[0]; - HSLFTextParagraph tr2 = ss.getSlides()[0].getTextRuns()[1]; + HSLFTextParagraph tr1 = ss.getSlides().get(0).getTextParagraphs().get(0); + HSLFTextParagraph tr2 = ss.getSlides().get(0).getTextParagraphs().get(1); // Ensure the text lengths are as we'd expect to start with assertEquals(1, ss.getSlides().length); - assertEquals(2, ss.getSlides()[0].getTextRuns().length); - assertEquals(30, tr1.getText().length()); - assertEquals(179, tr2.getText().length()); + assertEquals(2, ss.getSlides().get(0).getTextParagraphs().length); + assertEquals(30, tr1.getRawText().length()); + assertEquals(179, tr2.getRawText().length()); - assertEquals(1, tr1.getRichTextRuns().length); - assertEquals(30, tr1.getRichTextRuns()[0].getLength()); - assertEquals(30, tr1.getRichTextRuns()[0].getText().length()); - assertEquals(31, tr1.getRichTextRuns()[0]._getRawCharacterStyle().getCharactersCovered()); - assertEquals(31, tr1.getRichTextRuns()[0]._getRawParagraphStyle().getCharactersCovered()); + assertEquals(1, tr1.getTextRuns().length); + assertEquals(30, tr1.getTextRuns().get(0).getLength()); + assertEquals(30, tr1.getTextRuns().get(0).getRawText().length()); + assertEquals(31, tr1.getTextRuns().get(0)._getRawCharacterStyle().getCharactersCovered()); + assertEquals(31, tr1.getTextRuns().get(0)._getRawParagraphStyle().getCharactersCovered()); // Set the text to be as it is now - tr1.setText( tr1.getText() ); + tr1.setText( tr1.getRawText() ); // Check the text lengths are still right - assertEquals(30, tr1.getText().length()); - assertEquals(179, tr2.getText().length()); + assertEquals(30, tr1.getRawText().length()); + assertEquals(179, tr2.getRawText().length()); - assertEquals(1, tr1.getRichTextRuns().length); - assertEquals(30, tr1.getRichTextRuns()[0].getLength()); - assertEquals(30, tr1.getRichTextRuns()[0].getText().length()); - assertEquals(31, tr1.getRichTextRuns()[0]._getRawCharacterStyle().getCharactersCovered()); - assertEquals(31, tr1.getRichTextRuns()[0]._getRawParagraphStyle().getCharactersCovered()); + assertEquals(1, tr1.getTextRuns().length); + assertEquals(30, tr1.getTextRuns().get(0).getLength()); + assertEquals(30, tr1.getTextRuns().get(0).getRawText().length()); + assertEquals(31, tr1.getTextRuns().get(0)._getRawCharacterStyle().getCharactersCovered()); + assertEquals(31, tr1.getTextRuns().get(0)._getRawParagraphStyle().getCharactersCovered()); // Write the slideshow out to a byte array @@ -110,33 +114,34 @@ public final class TestTextRunReWrite extends TestCase { } } + @Test public void testWritesOutTheSameRich() throws Exception { // Grab the first text run on the first sheet - HSLFTextParagraph tr1 = ss.getSlides()[0].getTextRuns()[0]; + HSLFTextParagraph tr1 = ss.getSlides().get(0).getTextParagraphs().get(0); // Get the first rich text run - HSLFTextRun rtr1 = tr1.getRichTextRuns()[0]; + HSLFTextRun rtr1 = tr1.getTextRuns().get(0); // Check that the text sizes are as expected - assertEquals(1, tr1.getRichTextRuns().length); - assertEquals(30, tr1.getText().length()); - assertEquals(30, tr1.getRichTextRuns()[0].getText().length()); + assertEquals(1, tr1.getTextRuns().length); + assertEquals(30, tr1.getRawText().length()); + assertEquals(30, tr1.getTextRuns().get(0).getRawText().length()); assertEquals(30, rtr1.getLength()); - assertEquals(30, rtr1.getText().length()); + assertEquals(30, rtr1.getRawText().length()); assertEquals(31, rtr1._getRawCharacterStyle().getCharactersCovered()); assertEquals(31, rtr1._getRawParagraphStyle().getCharactersCovered()); // Set the text to be as it is now - rtr1.setText( rtr1.getText() ); - rtr1 = tr1.getRichTextRuns()[0]; + rtr1.setText( rtr1.getRawText() ); + rtr1 = tr1.getTextRuns().get(0); // Check that the text sizes are still as expected - assertEquals(1, tr1.getRichTextRuns().length); - assertEquals(30, tr1.getText().length()); - assertEquals(30, tr1.getRichTextRuns()[0].getText().length()); + assertEquals(1, tr1.getTextRuns().length); + assertEquals(30, tr1.getRawText().length()); + assertEquals(30, tr1.getTextRuns().get(0).getRawText().length()); assertEquals(30, rtr1.getLength()); - assertEquals(30, rtr1.getText().length()); + assertEquals(30, rtr1.getRawText().length()); assertEquals(31, rtr1._getRawCharacterStyle().getCharactersCovered()); assertEquals(31, rtr1._getRawParagraphStyle().getCharactersCovered()); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java index 5666b8db0e..f57d1548be 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestTextShape.java @@ -34,7 +34,7 @@ import java.util.Map; import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.sl.usermodel.ShapeType; import org.junit.Test; @@ -49,13 +49,13 @@ public final class TestTextShape { @Test public void createAutoShape(){ HSLFTextShape shape = new HSLFAutoShape(ShapeType.TRAPEZOID); - assertNull(shape.getTextParagraph()); + assertNull(shape.getTextParagraphs()); assertNull(shape.getText()); assertNull(shape.getEscherTextboxWrapper()); HSLFTextParagraph run = shape.createTextRun(); assertNotNull(run); - assertNotNull(shape.getTextParagraph()); + assertNotNull(shape.getTextParagraphs()); assertNotNull(shape.getEscherTextboxWrapper()); assertEquals("", shape.getText()); assertSame(run, shape.createTextRun()); @@ -65,13 +65,13 @@ public final class TestTextShape { @Test public void createTextBox(){ HSLFTextShape shape = new HSLFTextBox(); - HSLFTextParagraph run = shape.getTextParagraph(); + HSLFTextParagraph run = shape.getTextParagraphs(); assertNotNull(run); assertNotNull(shape.getText()); assertNotNull(shape.getEscherTextboxWrapper()); assertSame(run, shape.createTextRun()); - assertNotNull(shape.getTextParagraph()); + assertNotNull(shape.getTextParagraphs()); assertNotNull(shape.getEscherTextboxWrapper()); assertEquals("", shape.getText()); @@ -93,41 +93,41 @@ public final class TestTextShape { for (int i = 0; i < shape.length; i++) { assertTrue("Expected TextShape but found " + shape[i].getClass().getName(), shape[i] instanceof HSLFTextShape); HSLFTextShape tx = (HSLFTextShape)shape[i]; - HSLFTextParagraph run = tx.getTextParagraph(); + HSLFTextParagraph run = tx.getTextParagraphs(); assertNotNull(run); int runType = run.getRunType(); ShapeType type = shape[i].getShapeType(); switch (type){ case TEXT_BOX: - assertEquals("Text in a TextBox", run.getText()); + assertEquals("Text in a TextBox", run.getRawText()); break; case RECT: if(runType == TextHeaderAtom.OTHER_TYPE) - assertEquals("Rectangle", run.getText()); + assertEquals("Rectangle", run.getRawText()); else if(runType == TextHeaderAtom.TITLE_TYPE) - assertEquals("Title Placeholder", run.getText()); + assertEquals("Title Placeholder", run.getRawText()); break; case OCTAGON: - assertEquals("Octagon", run.getText()); + assertEquals("Octagon", run.getRawText()); break; case ELLIPSE: - assertEquals("Ellipse", run.getText()); + assertEquals("Ellipse", run.getRawText()); break; case ROUND_RECT: - assertEquals("RoundRectangle", run.getText()); + assertEquals("RoundRectangle", run.getRawText()); break; default: fail("Unexpected shape: " + shape[i].getShapeName()); } - lst1.add(run.getText()); + lst1.add(run.getRawText()); } List lst2 = new ArrayList(); - HSLFTextParagraph[] run = slide.getTextRuns(); + HSLFTextParagraph[] run = slide.getTextParagraphs(); for (int i = 0; i < run.length; i++) { - lst2.add(run[i].getText()); + lst2.add(run[i].getRawText()); } assertTrue(lst1.containsAll(lst2)); @@ -162,12 +162,12 @@ public final class TestTextShape { assertTrue(shape[0] instanceof HSLFTextShape); shape1 = (HSLFTextShape)shape[0]; assertEquals(ShapeType.TEXT_BOX, shape1.getShapeType()); - assertEquals("Hello, World!", shape1.getTextParagraph().getText()); + assertEquals("Hello, World!", shape1.getTextParagraphs().getRawText()); assertTrue(shape[1] instanceof HSLFTextShape); shape1 = (HSLFTextShape)shape[1]; assertEquals(ShapeType.RIGHT_ARROW, shape1.getShapeType()); - assertEquals("Testing TextShape", shape1.getTextParagraph().getText()); + assertEquals("Testing TextShape", shape1.getTextParagraphs().getRawText()); } @Test @@ -188,28 +188,28 @@ public final class TestTextShape { HSLFTextShape tx; tx = map.get("TEST1"); - assertEquals(0.1, tx.getMarginLeft()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.1, tx.getMarginRight()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.39, tx.getMarginTop()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginBottom()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getLeftInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getRightInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.39, tx.getTopInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getBottomInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); tx = map.get("TEST2"); - assertEquals(0.1, tx.getMarginLeft()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.1, tx.getMarginRight()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginTop()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.39, tx.getMarginBottom()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getLeftInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getRightInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getTopInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.39, tx.getBottomInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); tx = map.get("TEST3"); - assertEquals(0.39, tx.getMarginLeft()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.1, tx.getMarginRight()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginTop()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginBottom()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.39, tx.getLeftInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getRightInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getTopInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getBottomInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); tx = map.get("TEST4"); - assertEquals(0.1, tx.getMarginLeft()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.39, tx.getMarginRight()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginTop()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); - assertEquals(0.05, tx.getMarginBottom()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.1, tx.getLeftInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.39, tx.getRightInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getTopInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); + assertEquals(0.05, tx.getBottomInset()*HSLFShape.EMU_PER_POINT/HSLFShape.EMU_PER_INCH, 0.01); } @Test @@ -222,14 +222,14 @@ public final class TestTextShape { HSLFTextShape sh0 = (HSLFTextShape)sh[0]; assertEquals(null, sh0.getText()); - assertEquals(null, sh0.getTextParagraph()); + assertEquals(null, sh0.getTextParagraphs()); HSLFTextShape sh1 = (HSLFTextShape)sh[1]; assertEquals(null, sh1.getText()); - assertEquals(null, sh1.getTextParagraph()); + assertEquals(null, sh1.getTextParagraphs()); HSLFTextShape sh2 = (HSLFTextShape)sh[2]; assertEquals("this box should be shown just once", sh2.getText()); - assertEquals(-1, sh2.getTextParagraph().getIndex()); + assertEquals(-1, sh2.getTextParagraphs().getIndex()); } } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TextPainterTest.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TextPainterTest.java index 7e37b47a43..f11d299c90 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TextPainterTest.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TextPainterTest.java @@ -19,7 +19,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.hslf.record.StyleTextPropAtom; import org.apache.poi.hslf.record.TextCharsAtom; import org.apache.poi.hslf.record.TextHeaderAtom; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hssf.usermodel.DummyGraphics2d; import org.junit.Test; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java index 60aee0f49d..f7ee1f9262 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestCurrentUserAtom.java @@ -25,7 +25,7 @@ import java.io.InputStream; import org.apache.poi.POIDataSamples; import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.poifs.filesystem.DocumentEntry; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.junit.Test; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocument.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocument.java index d7de61c877..8018ba3b86 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocument.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocument.java @@ -19,7 +19,7 @@ package org.apache.poi.hslf.record; import junit.framework.TestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.poifs.filesystem.*; import org.apache.poi.POIDataSamples; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocumentEncryption.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocumentEncryption.java index 12c114b344..4f23e4998b 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocumentEncryption.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestDocumentEncryption.java @@ -34,10 +34,7 @@ import org.apache.poi.hpsf.PropertySet; import org.apache.poi.hpsf.PropertySetFactory; import org.apache.poi.hpsf.SummaryInformation; import org.apache.poi.hslf.exceptions.EncryptedPowerPointFileException; -import org.apache.poi.hslf.model.HSLFSlide; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; -import org.apache.poi.hslf.usermodel.HSLFPictureData; -import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.*; import org.apache.poi.hssf.record.crypto.Biff8EncryptionKey; import org.apache.poi.poifs.crypt.CryptoFunctions; import org.apache.poi.poifs.crypt.EncryptionInfo; @@ -147,7 +144,7 @@ public class TestDocumentEncryption { HSLFSlideShow ss = new HSLFSlideShow(hss); HSLFSlide slide = ss.getSlides()[0]; - assertEquals("Dominic Salemno", slide.getTextRuns()[0].getText()); + assertEquals("Dominic Salemno", slide.getTextParagraphs()[0].getRawText()); String picCmp[][] = { {"0","nKsDTKqxTCR8LFkVVWlP9GSTvZ0="}, diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExHyperlink.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExHyperlink.java index f712e20a6d..de5ee42b7c 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExHyperlink.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExHyperlink.java @@ -25,8 +25,8 @@ import java.util.List; import junit.framework.AssertionFailedError; import junit.framework.TestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.POIDataSamples; /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExObjList.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExObjList.java index 836016666e..bf596faed8 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExObjList.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestExObjList.java @@ -20,8 +20,8 @@ package org.apache.poi.hslf.record; import junit.framework.TestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.usermodel.HSLFSlideShow; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.POIDataSamples; /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestRecordContainer.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestRecordContainer.java index cecf3ee319..67bbd03175 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestRecordContainer.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestRecordContainer.java @@ -20,7 +20,7 @@ package org.apache.poi.hslf.record; import junit.framework.TestCase; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; +import org.apache.poi.hslf.usermodel.HSLFSlideShowImpl; import org.apache.poi.POIDataSamples; /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java index 4b1ef6c988..4dad61a6cb 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/record/TestSlideAtom.java @@ -78,7 +78,7 @@ public final class TestSlideAtom extends TestCase { public void testSSSlideInfoAtom() throws Exception { HSLFSlideShow ss = new HSLFSlideShow(); - org.apache.poi.hslf.model.HSLFSlide slide1 = ss.createSlide(), slide2 = ss.createSlide(); + org.apache.poi.hslf.usermodel.HSLFSlide slide1 = ss.createSlide(), slide2 = ss.createSlide(); slide2.setHidden(true); ByteArrayOutputStream bos = new ByteArrayOutputStream(4096); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java index 42fbf9113d..1dcd58ca37 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java @@ -98,16 +98,16 @@ public final class TestBugs { notes = ppt.getSlides()[0].getNotesSheet(); assertNotNull(notes); - txrun = notes.getTextRuns()[0]; + txrun = notes.getTextParagraphs()[0]; assertEquals("Notes-1", txrun.getRawText()); - assertEquals(false, txrun.getRichTextRuns()[0].isBold()); + assertEquals(false, txrun.getTextRuns()[0].isBold()); //notes for the second slide are in bold notes = ppt.getSlides()[1].getNotesSheet(); assertNotNull(notes); - txrun = notes.getTextRuns()[0]; + txrun = notes.getTextParagraphs()[0]; assertEquals("Notes-2", txrun.getRawText()); - assertEquals(true, txrun.getRichTextRuns()[0].isBold()); + assertEquals(true, txrun.getTextRuns()[0].isBold()); } @@ -134,7 +134,7 @@ public final class TestBugs { HSLFNotes notes = slide[i].getNotesSheet(); if (notesMap.containsKey(slideNumber)){ assertNotNull(notes); - String text = notes.getTextRuns()[0].getRawText(); + String text = notes.getTextParagraphs()[0].getRawText(); String startingPhrase = notesMap.get(slideNumber); assertTrue("Notes for slide " + slideNumber + " must start with " + startingPhrase , text.startsWith(startingPhrase)); @@ -158,7 +158,7 @@ public final class TestBugs { for (int j = 0; j < sh.length; j++) { if( sh[j] instanceof HSLFTextBox){ HSLFTextBox txt = (HSLFTextBox)sh[j]; - assertNotNull(txt.getTextParagraph()); + assertNotNull(txt.getTextParagraphs()); } } } @@ -202,8 +202,8 @@ public final class TestBugs { HSLFSlide[] slide = ppt.getSlides(); for (int i = 0; i < slide.length; i++) { HSLFMasterSheet master = slide[i].getMasterSheet(); - if (i == 0) assertTrue(master instanceof TitleMaster); //the first slide follows TitleMaster - else assertTrue(master instanceof SlideMaster); + if (i == 0) assertTrue(master instanceof HSLFTitleMaster); //the first slide follows TitleMaster + else assertTrue(master instanceof HSLFSlideMaster); } } @@ -301,7 +301,7 @@ public final class TestBugs { HSLFSlide[] slide = ppt.getSlides(); assertEquals(1, slide.length); - HSLFTextParagraph[] runs = slide[0].getTextRuns(); + HSLFTextParagraph[] runs = slide[0].getTextParagraphs(); assertEquals(4, runs.length); Set txt = new HashSet(); @@ -329,21 +329,21 @@ public final class TestBugs { // Check the first slide HSLFSlide slide = ppt.getSlides()[0]; - HSLFTextParagraph[] slTr = slide.getTextRuns(); + HSLFTextParagraph[] slTr = slide.getTextParagraphs(); // Has two text runs, one from slide text, one from drawing assertEquals(2, slTr.length); assertEquals(false, slTr[0].isDrawingBased()); assertEquals(true, slTr[1].isDrawingBased()); - assertEquals("First run", slTr[0].getText()); - assertEquals("Second run", slTr[1].getText()); + assertEquals("First run", slTr[0].getRawText()); + assertEquals("Second run", slTr[1].getRawText()); // Check the shape based text runs List lst = new ArrayList(); HSLFShape[] shape = slide.getShapes(); for (int i = 0; i < shape.length; i++) { if( shape[i] instanceof HSLFTextShape){ - HSLFTextParagraph textRun = ((HSLFTextShape)shape[i]).getTextParagraph(); + HSLFTextParagraph textRun = ((HSLFTextShape)shape[i]).getTextParagraphs(); if(textRun != null) { lst.add(textRun); } @@ -354,7 +354,7 @@ public final class TestBugs { assertEquals(1, lst.size()); // And it should be the second one - assertEquals("Second run", lst.get(0).getText()); + assertEquals("Second run", lst.get(0).getRawText()); } /** @@ -402,11 +402,11 @@ public final class TestBugs { assertEquals(1, sh.length); assertTrue(sh[0] instanceof HSLFTextShape); HSLFTextShape tx = (HSLFTextShape)sh[0]; - assertEquals("Fundera, planera och involvera.", tx.getTextParagraph().getText()); + assertEquals("Fundera, planera och involvera.", tx.getTextParagraphs().getRawText()); - HSLFTextParagraph[] run = slide.getTextRuns(); + HSLFTextParagraph[] run = slide.getTextParagraphs(); assertEquals(1, run.length); - assertEquals("Fundera, planera och involvera.", run[0].getText()); + assertEquals("Fundera, planera och involvera.", run[0].getRawText()); } /** @@ -429,7 +429,7 @@ public final class TestBugs { public void bug49648() throws Exception { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("49648.ppt")); for(HSLFSlide slide : ppt.getSlides()) { - for(HSLFTextParagraph run : slide.getTextRuns()) { + for(HSLFTextParagraph run : slide.getTextParagraphs()) { String text = run.getRawText(); text.replace("{txtTot}", "With \u0123\u1234\u5678 unicode"); run.setRawText(text); @@ -487,7 +487,7 @@ public final class TestBugs { str = str.replace("$$DATE$$", new Date().toString()); tb.setText(str); - HSLFTextParagraph tr = tb.getTextParagraph(); + HSLFTextParagraph tr = tb.getTextParagraphs(); assertEquals(str.length()+1,tr.getStyleTextPropAtom().getParagraphStyles().getFirst().getCharactersCovered()); assertEquals(str.length()+1,tr.getStyleTextPropAtom().getCharacterStyles().getFirst().getCharactersCovered()); } @@ -538,7 +538,7 @@ public final class TestBugs { // Check the number of text runs based on the slide (not textbox) // Will have skipped the empty one int str = 0; - for (HSLFTextParagraph tr : _slides[0].getTextRuns()) { + for (HSLFTextParagraph tr : _slides[0].getTextParagraphs()) { if (! tr.isDrawingBased()) str++; } assertEquals(1, str); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java index 37b7bb6965..3638bad82e 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestFontRendering.java @@ -39,7 +39,6 @@ import java.util.Map; import javax.imageio.ImageIO; import org.apache.poi.POIDataSamples; -import org.apache.poi.hslf.model.HSLFSlide; import org.apache.poi.hslf.model.TextPainter; import org.apache.poi.util.TempFile; import org.junit.Ignore; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestMostRecentRecords.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestMostRecentRecords.java index 088dbb0cee..1cb9c7d9fd 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestMostRecentRecords.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestMostRecentRecords.java @@ -21,7 +21,6 @@ package org.apache.poi.hslf.usermodel; import junit.framework.TestCase; import org.apache.poi.hslf.*; -import org.apache.poi.hslf.model.HSLFSlideShowImpl; import org.apache.poi.hslf.record.*; import org.apache.poi.POIDataSamples; diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNotesText.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNotesText.java index 22b40a22e2..570fb5883a 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNotesText.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNotesText.java @@ -43,18 +43,18 @@ public final class TestNotesText extends TestCase { HSLFNotes notes = ss.getNotes()[0]; String[] expectText = new String[] {"These are the notes for page 1"}; - assertEquals(expectText.length, notes.getTextRuns().length); + assertEquals(expectText.length, notes.getTextParagraphs().length); for(int i=0; i(text a)(text a)(text b) // TR: // (text) - HSLFTextParagraph[] s7tr = slideSevenC.getTextRuns(); - HSLFTextRun[] s7rtr0 = s7tr[0].getRichTextRuns(); - HSLFTextRun[] s7rtr1 = s7tr[1].getRichTextRuns(); - HSLFTextRun[] s7rtr2 = s7tr[2].getRichTextRuns(); + HSLFTextParagraph[] s7tr = slideSevenC.getTextParagraphs(); + HSLFTextRun[] s7rtr0 = s7tr[0].getTextRuns(); + HSLFTextRun[] s7rtr1 = s7tr[1].getTextRuns(); + HSLFTextRun[] s7rtr2 = s7tr[2].getTextRuns(); assertEquals(1, s7rtr0.length); assertEquals(3, s7rtr1.length); @@ -332,10 +332,10 @@ public final class TestRichTextRun extends POITestCase { assertMatchesFileC(ssRichC); HSLFSlide slideSevenC = ssRichC.getSlides()[6]; - HSLFTextParagraph[] s7tr = slideSevenC.getTextRuns(); - HSLFTextRun[] s7rtr0 = s7tr[0].getRichTextRuns(); - HSLFTextRun[] s7rtr1 = s7tr[1].getRichTextRuns(); - HSLFTextRun[] s7rtr2 = s7tr[2].getRichTextRuns(); + HSLFTextParagraph[] s7tr = slideSevenC.getTextParagraphs(); + HSLFTextRun[] s7rtr0 = s7tr[0].getTextRuns(); + HSLFTextRun[] s7rtr1 = s7tr[1].getTextRuns(); + HSLFTextRun[] s7rtr2 = s7tr[2].getTextRuns(); String oldText; @@ -343,8 +343,8 @@ public final class TestRichTextRun extends POITestCase { // Need to ensure it's a run that really has styles! oldText = s7rtr2[0].getRawText(); s7rtr2[0].setText( oldText ); - assertEquals(oldText, s7rtr2[0].getText()); - assertEquals(oldText, s7tr[2].getText()); + assertEquals(oldText, s7rtr2[0].getRawText()); + assertEquals(oldText, s7tr[2].getRawText()); assertEquals(oldText.length() + 1, s7rtr2[0]._getRawCharacterStyle().getCharactersCovered()); assertEquals(oldText.length() + 1, s7rtr2[0]._getRawParagraphStyle().getCharactersCovered()); assertMatchesSLTWC(ssRichC); @@ -353,7 +353,7 @@ public final class TestRichTextRun extends POITestCase { // Reset the text on a shared paragraph oldText = s7rtr1[2].getRawText(); s7rtr1[2].setText( oldText ); - assertEquals(oldText, s7rtr1[2].getText()); + assertEquals(oldText, s7rtr1[2].getRawText()); assertEquals(oldText.length() + 1, s7rtr1[2]._getRawCharacterStyle().getCharactersCovered()); assertMatchesSLTWC(ssRichC); assertMatchesFileC(ssRichC); @@ -450,9 +450,9 @@ if(false) { HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("ParagraphStylesShorterThanCharStyles.ppt")); HSLFSlide[] sl = ppt.getSlides(); for (int i = 0; i < sl.length; i++) { - HSLFTextParagraph[] txt = sl[i].getTextRuns(); + HSLFTextParagraph[] txt = sl[i].getTextParagraphs(); for (int j = 0; j < txt.length; j++) { - HSLFTextRun[] rt = txt[j].getRichTextRuns(); + HSLFTextRun[] rt = txt[j].getTextRuns(); for (int k = 0; k < rt.length; k++) { int indent = rt[k].getIndentLevel(); assertTrue(indent >= 0 && indent <= 4 ); @@ -471,12 +471,12 @@ if(false) { HSLFSlide[] slide = ppt.getSlides(); assertEquals(2, slide.length); - txt = slide[0].getTextRuns(); + txt = slide[0].getTextParagraphs(); assertEquals(2, txt.length); assertEquals("Title text", txt[0].getRawText()); - assertEquals(1, txt[0].getRichTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + assertEquals(1, txt[0].getTextRuns().length); + rt = txt[0].getTextRuns()[0]; assertFalse(rt.isBullet()); assertEquals( @@ -484,13 +484,13 @@ if(false) { "follows the design pattern\r" + "Defined in the slide master\r" + "and has bullets by default", txt[1].getRawText()); - assertEquals(1, txt[1].getRichTextRuns().length); - rt = txt[1].getRichTextRuns()[0]; + assertEquals(1, txt[1].getTextRuns().length); + rt = txt[1].getTextRuns()[0]; assertEquals('\u2022', rt.getBulletChar()); assertTrue(rt.isBullet()); - txt = slide[1].getTextRuns(); + txt = slide[1].getTextParagraphs(); assertEquals(2, txt.length); assertEquals( @@ -498,16 +498,16 @@ if(false) { "With bullets\r" + "That follow the design pattern\r" + "From the slide master", txt[0].getRawText()); - assertEquals(1, txt[0].getRichTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + assertEquals(1, txt[0].getTextRuns().length); + rt = txt[0].getTextRuns()[0]; assertTrue(rt.isBullet()); assertEquals('\u2022', rt.getBulletChar()); assertEquals( "I\u2019m a text box with user-defined\r" + "bullet character", txt[1].getRawText()); - assertEquals(1, txt[1].getRichTextRuns().length); - rt = txt[1].getRichTextRuns()[0]; + assertEquals(1, txt[1].getTextRuns().length); + rt = txt[1].getTextRuns()[0]; assertTrue(rt.isBullet()); assertEquals('\u263A', rt.getBulletChar()); } @@ -518,7 +518,7 @@ if(false) { HSLFSlide slide = ppt.createSlide(); HSLFTextBox shape = new HSLFTextBox(); - HSLFTextRun rt = shape.getTextParagraph().getRichTextRuns()[0]; + HSLFTextRun rt = shape.getTextParagraphs().getTextRuns()[0]; shape.setText( "Hello, World!\r" + "This should be\r" + @@ -547,7 +547,7 @@ if(false) { ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); slide = ppt.getSlides()[0]; shape = (HSLFTextBox)slide.getShapes()[0]; - rt = shape.getTextParagraph().getRichTextRuns()[0]; + rt = shape.getTextParagraphs().getTextRuns()[0]; assertEquals(42, rt.getFontSize()); assertEquals(true, rt.isBullet()); assertEquals(50, rt.getTextOffset()); @@ -564,38 +564,38 @@ if(false) { HSLFSlide[] slides = ppt.getSlides(); assertEquals(2, slides.length); - txt = slides[0].getTextRuns(); + txt = slides[0].getTextParagraphs(); assertEquals(2, txt.length); assertEquals("Title text", txt[0].getRawText()); - assertEquals(1, txt[0].getRichTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + assertEquals(1, txt[0].getTextRuns().length); + rt = txt[0].getTextRuns()[0]; assertFalse(rt.isBullet()); // Add some new text txt[0].appendText("Foo! I'm new!"); - assertEquals(2, txt[0].getRichTextRuns().length); + assertEquals(2, txt[0].getTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + rt = txt[0].getTextRuns()[0]; assertFalse(rt.isBold()); - assertEquals("Title text", rt.getText()); - rt = txt[0].getRichTextRuns()[1]; + assertEquals("Title text", rt.getRawText()); + rt = txt[0].getTextRuns()[1]; assertFalse(rt.isBold()); - assertEquals("Foo! I'm new!", rt.getText()); + assertEquals("Foo! I'm new!", rt.getRawText()); rt.setBold(true); // And some more txt[0].appendText("Me too!"); - assertEquals(3, txt[0].getRichTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + assertEquals(3, txt[0].getTextRuns().length); + rt = txt[0].getTextRuns()[0]; assertFalse(rt.isBold()); - assertEquals("Title text", rt.getText()); - rt = txt[0].getRichTextRuns()[1]; + assertEquals("Title text", rt.getRawText()); + rt = txt[0].getTextRuns()[1]; assertTrue(rt.isBold()); - assertEquals("Foo! I'm new!", rt.getText()); - rt = txt[0].getRichTextRuns()[2]; + assertEquals("Foo! I'm new!", rt.getRawText()); + rt = txt[0].getTextRuns()[2]; assertFalse(rt.isBold()); - assertEquals("Me too!", rt.getText()); + assertEquals("Me too!", rt.getRawText()); // Save and re-open ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -607,18 +607,18 @@ if(false) { assertEquals(2, slides.length); - txt = slides[0].getTextRuns(); + txt = slides[0].getTextParagraphs(); assertEquals(2, txt.length); - assertEquals(3, txt[0].getRichTextRuns().length); - rt = txt[0].getRichTextRuns()[0]; + assertEquals(3, txt[0].getTextRuns().length); + rt = txt[0].getTextRuns()[0]; assertFalse(rt.isBold()); - assertEquals("Title text", rt.getText()); - rt = txt[0].getRichTextRuns()[1]; + assertEquals("Title text", rt.getRawText()); + rt = txt[0].getTextRuns()[1]; assertTrue(rt.isBold()); - assertEquals("Foo! I'm new!", rt.getText()); - rt = txt[0].getRichTextRuns()[2]; + assertEquals("Foo! I'm new!", rt.getRawText()); + rt = txt[0].getTextRuns()[2]; assertFalse(rt.isBold()); - assertEquals("Me too!", rt.getText()); + assertEquals("Me too!", rt.getRawText()); // FileOutputStream fout = new FileOutputStream("/tmp/foo.ppt"); // ppt.write(fout); @@ -634,17 +634,17 @@ if(false) { assertEquals(1, slides.length); // One block of text within that - txt = slides[0].getTextRuns(); + txt = slides[0].getTextParagraphs(); assertEquals(1, txt.length); // One rich block of text in that - text is all the same style // TODO Is this completely correct? - rts = txt[0].getRichTextRuns(); + rts = txt[0].getTextRuns(); assertEquals(1, rts.length); rt = rts[0]; // Check we can get the english text out of that - String text = rt.getText(); + String text = rt.getRawText(); assertContains(text, "Single byte"); // And the chinese assertContains(text, "\uff8a\uff9d\uff76\uff78"); diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSheetText.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSheetText.java index fda2aba0d0..000166b754 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSheetText.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestSheetText.java @@ -43,18 +43,18 @@ public final class TestSheetText extends TestCase { HSLFSheet slideOne = ss.getSlides()[0]; String[] expectText = new String[] {"This is a test title","This is a test subtitle\nThis is on page 1"}; - assertEquals(expectText.length, slideOne.getTextRuns().length); + assertEquals(expectText.length, slideOne.getTextParagraphs().length); for(int i=0; i textParas = slideOne.getTextParagraphs(); + + assertEquals(2, textParas.size()); + + // Get text works with \n + assertEquals("This is a test title", textParas.get(0).getTextRuns().get(0).getRawText()); + assertEquals("This is a test subtitle\nThis is on page 1", textParas.get(1).getTextRuns().get(0).getRawText()); + + // Raw text has \r instead + assertEquals("This is a test title", textParas.get(0).getTextRuns().get(0).getRawText()); + assertEquals("This is a test subtitle\rThis is on page 1", textParas.get(1).getTextRuns().get(0).getRawText()); + + + // Now check on a rich text run + HSLFSlide slideOneR = ssRich.getSlides().get(0); + List textRunsR = slideOneR.getTextParagraphs(); + + assertEquals(2, textRunsR.size()); + assertEquals("This is a title, it\u2019s in black", textRunsR.get(0).getTextRuns().get(0).getRawText()); + assertEquals("This is the subtitle, in bold\nThis bit is blue and italic\nThis bit is red (normal)", textRunsR.get(1).getTextRuns().get(0).getRawText()); + assertEquals("This is a title, it\u2019s in black", textRunsR.get(0).getTextRuns().get(0).getRawText()); + assertEquals("This is the subtitle, in bold\rThis bit is blue and italic\rThis bit is red (normal)", textRunsR.get(1).getTextRuns().get(0).getRawText()); + } + + /** + * Test to ensure changing non rich text bytes->bytes works correctly + */ + @Test + public void testSetText() { + HSLFSlide slideOne = ss.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + HSLFTextParagraph run = textRuns.get(0); + HSLFTextRun tr = run.getTextRuns().get(0); + + // Check current text + assertEquals("This is a test title", tr.getRawText()); + + // Change + String changeTo = "New test title"; + tr.setText(changeTo); + assertEquals(changeTo, tr.getRawText()); + + // Ensure trailing \n's are NOT stripped, it is legal to set a text with a trailing '\r' + tr.setText(changeTo + "\n"); + assertEquals(changeTo + "\n", tr.getRawText()); + } + + /** + * Test to ensure that changing non rich text between bytes and + * chars works correctly + */ + @Test + public void testAdvancedSetText() { + HSLFSlide slideOne = ss.getSlides().get(0); + List paras = slideOne.getTextParagraphs(); + HSLFTextParagraph para = paras.get(0); + + TextHeaderAtom tha = null; + TextBytesAtom tba = null; + TextCharsAtom tca = null; + for (Record r : para.getRecords()) { + if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r; + else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r; + else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r; + } + + + // Bytes -> Bytes + assertNull(tca); + assertNotNull(tba); + // assertFalse(run._isUnicode); + assertEquals("This is a test title", para.getTextRuns().get(0).getRawText()); + + String changeBytesOnly = "New Test Title"; + HSLFTextParagraph.setText(paras, changeBytesOnly); + para = paras.get(0); + tha = null; tba = null; tca = null; + for (Record r : para.getRecords()) { + if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r; + else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r; + else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r; + } + + assertEquals(changeBytesOnly, HSLFTextParagraph.getRawText(paras)); + assertNull(tca); + assertNotNull(tba); + + // Bytes -> Chars + assertNull(tca); + assertNotNull(tba); + assertEquals(changeBytesOnly, HSLFTextParagraph.getRawText(paras)); + + String changeByteChar = "This is a test title with a '\u0121' g with a dot"; + HSLFTextParagraph.setText(paras, changeByteChar); + para = paras.get(0); + tha = null; tba = null; tca = null; + for (Record r : para.getRecords()) { + if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r; + else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r; + else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r; + } + + assertEquals(changeByteChar, HSLFTextParagraph.getRawText(paras)); + assertNotNull(tca); + assertNull(tba); + + // Chars -> Chars + assertNull(tba); + assertNotNull(tca); + assertEquals(changeByteChar, HSLFTextParagraph.getRawText(paras)); + + String changeCharChar = "This is a test title with a '\u0147' N with a hat"; + HSLFTextParagraph.setText(paras, changeCharChar); + para = paras.get(0); + tha = null; tba = null; tca = null; + for (Record r : para.getRecords()) { + if (r instanceof TextHeaderAtom) tha = (TextHeaderAtom)r; + else if (r instanceof TextBytesAtom) tba = (TextBytesAtom)r; + else if (r instanceof TextCharsAtom) tca = (TextCharsAtom)r; + } + + assertEquals(changeCharChar, HSLFTextParagraph.getRawText(paras)); + assertNotNull(tca); + assertNull(tba); + } + + /** + * Tests to ensure that non rich text has the right default rich text run + * set up for it + */ + @Test + public void testGetRichTextNonRich() { + HSLFSlide slideOne = ss.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + + assertEquals(2, textRuns.size()); + + HSLFTextParagraph trA = textRuns.get(0); + HSLFTextParagraph trB = textRuns.get(1); + + assertEquals(1, trA.getTextRuns().size()); + assertEquals(1, trB.getTextRuns().size()); + + HSLFTextRun rtrA = trA.getTextRuns().get(0); + HSLFTextRun rtrB = trB.getTextRuns().get(0); + + assertEquals(HSLFTextParagraph.getRawText(textRuns.subList(0, 0)), rtrA.getRawText()); + assertEquals(HSLFTextParagraph.getRawText(textRuns.subList(1, 1)), rtrB.getRawText()); + +// assertNull(rtrA._getRawCharacterStyle()); +// assertNull(rtrA._getRawParagraphStyle()); +// assertNull(rtrB._getRawCharacterStyle()); +// assertNull(rtrB._getRawParagraphStyle()); + } + + /** + * Tests to ensure that the rich text runs are built up correctly + */ + @Test + public void testGetRichText() { + HSLFSlide slideOne = ssRich.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + + assertEquals(2, textRuns.size()); + + HSLFTextParagraph trA = textRuns.get(0); + HSLFTextParagraph trB = textRuns.get(1); + + assertEquals(1, trA.getTextRuns().size()); + assertEquals(3, trB.getTextRuns().size()); + + HSLFTextRun rtrA = trA.getTextRuns().get(0); + HSLFTextRun rtrB = trB.getTextRuns().get(0); + HSLFTextRun rtrC = trB.getTextRuns().get(1); + HSLFTextRun rtrD = trB.getTextRuns().get(2); + + assertEquals(HSLFTextParagraph.getRawText(textRuns.subList(0, 0)), rtrA.getRawText()); + + String trBstr = HSLFTextParagraph.getRawText(textRuns.subList(1, 1)); + assertEquals(trBstr.substring(0, 30), rtrB.getRawText()); + assertEquals(trBstr.substring(30,58), rtrC.getRawText()); + assertEquals(trBstr.substring(58,82), rtrD.getRawText()); + +// assertNull(rtrA._getRawCharacterStyle()); +// assertNull(rtrA._getRawParagraphStyle()); +// assertNotNull(rtrB._getRawCharacterStyle()); +// assertNotNull(rtrB._getRawParagraphStyle()); +// assertNotNull(rtrC._getRawCharacterStyle()); +// assertNotNull(rtrC._getRawParagraphStyle()); +// assertNotNull(rtrD._getRawCharacterStyle()); +// assertNotNull(rtrD._getRawParagraphStyle()); + + // Same paragraph styles +// assertEquals(rtrB._getRawParagraphStyle(), rtrC._getRawParagraphStyle()); +// assertEquals(rtrB._getRawParagraphStyle(), rtrD._getRawParagraphStyle()); + + // Different char styles +// assertFalse( rtrB._getRawCharacterStyle().equals( rtrC._getRawCharacterStyle() )); +// assertFalse( rtrB._getRawCharacterStyle().equals( rtrD._getRawCharacterStyle() )); +// assertFalse( rtrC._getRawCharacterStyle().equals( rtrD._getRawCharacterStyle() )); + } + + /** + * Tests to ensure that setting the text where the text isn't rich, + * ensuring that everything stays with the same default styling + */ + @Test + public void testSetTextWhereNotRich() { + HSLFSlide slideOne = ss.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + HSLFTextParagraph trB = textRuns.get(1); +// assertEquals(1, trB.getTextRuns().length); + + HSLFTextRun rtrB = trB.getTextRuns().get(0); +// assertEquals(trB.getRawText(), rtrB.getRawText()); +// assertNull(rtrB._getRawCharacterStyle()); +// assertNull(rtrB._getRawParagraphStyle()); + + // Change text via normal +// trB.setText("Test Foo Test"); + rtrB = trB.getTextRuns().get(0); +// assertEquals("Test Foo Test", trB.getRawText()); +// assertEquals("Test Foo Test", rtrB.getRawText()); +// assertNull(rtrB._getRawCharacterStyle()); +// assertNull(rtrB._getRawParagraphStyle()); + } + + /** + * Tests to ensure that setting the text where the text is rich + * sets everything to the same styling + */ + @Test + public void testSetTextWhereRich() { + HSLFSlide slideOne = ssRich.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + HSLFTextParagraph trB = textRuns.get(1); + assertEquals(3, trB.getTextRuns().size()); + + HSLFTextRun rtrB = trB.getTextRuns().get(0); + HSLFTextRun rtrC = trB.getTextRuns().get(1); + HSLFTextRun rtrD = trB.getTextRuns().get(2); +// TextPropCollection tpBP = rtrB._getRawParagraphStyle(); +// TextPropCollection tpBC = rtrB._getRawCharacterStyle(); +// TextPropCollection tpCP = rtrC._getRawParagraphStyle(); +// TextPropCollection tpCC = rtrC._getRawCharacterStyle(); +// TextPropCollection tpDP = rtrD._getRawParagraphStyle(); +// TextPropCollection tpDC = rtrD._getRawCharacterStyle(); + +// assertEquals(trB.getRawText().substring(0, 30), rtrB.getRawText()); +// assertNotNull(tpBP); +// assertNotNull(tpBC); +// assertNotNull(tpCP); +// assertNotNull(tpCC); +// assertNotNull(tpDP); +// assertNotNull(tpDC); +// assertTrue(tpBP.equals(tpCP)); +// assertTrue(tpBP.equals(tpDP)); +// assertTrue(tpCP.equals(tpDP)); +// assertFalse(tpBC.equals(tpCC)); +// assertFalse(tpBC.equals(tpDC)); +// assertFalse(tpCC.equals(tpDC)); + + // Change text via normal +// trB.setText("Test Foo Test"); + + // Ensure now have first style +// assertEquals(1, trB.getTextRuns().length); +// rtrB = trB.getTextRuns().get(0); +// assertEquals("Test Foo Test", trB.getRawText()); +// assertEquals("Test Foo Test", rtrB.getRawText()); +// assertNotNull(rtrB._getRawCharacterStyle()); +// assertNotNull(rtrB._getRawParagraphStyle()); +// assertEquals( tpBP, rtrB._getRawParagraphStyle() ); +// assertEquals( tpBC, rtrB._getRawCharacterStyle() ); + } + + /** + * Test to ensure the right stuff happens if we change the text + * in a rich text run, that doesn't happen to actually be rich + */ + @Test + public void testChangeTextInRichTextRunNonRich() { + HSLFSlide slideOne = ss.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + HSLFTextParagraph trB = textRuns.get(1); +// assertEquals(1, trB.getTextRuns().length); +// +// HSLFTextRun rtrB = trB.getTextRuns().get(0); +// assertEquals(trB.getRawText(), rtrB.getRawText()); +// assertNull(rtrB._getRawCharacterStyle()); +// assertNull(rtrB._getRawParagraphStyle()); + + // Change text via rich +// rtrB.setText("Test Test Test"); +// assertEquals("Test Test Test", trB.getRawText()); +// assertEquals("Test Test Test", rtrB.getRawText()); + + // Will now have dummy props +// assertNotNull(rtrB._getRawCharacterStyle()); +// assertNotNull(rtrB._getRawParagraphStyle()); + } + + /** + * Tests to ensure changing the text within rich text runs works + * correctly + */ + @Test + public void testChangeTextInRichTextRun() { + HSLFSlide slideOne = ssRich.getSlides().get(0); + List textRuns = slideOne.getTextParagraphs(); + HSLFTextParagraph trB = textRuns.get(1); + assertEquals(3, trB.getTextRuns().size()); + + // We start with 3 text runs, each with their own set of styles, + // but all sharing the same paragraph styles + HSLFTextRun rtrB = trB.getTextRuns().get(0); + HSLFTextRun rtrC = trB.getTextRuns().get(1); + HSLFTextRun rtrD = trB.getTextRuns().get(2); +// TextPropCollection tpBP = rtrB._getRawParagraphStyle(); +// TextPropCollection tpBC = rtrB._getRawCharacterStyle(); +// TextPropCollection tpCP = rtrC._getRawParagraphStyle(); +// TextPropCollection tpCC = rtrC._getRawCharacterStyle(); +// TextPropCollection tpDP = rtrD._getRawParagraphStyle(); +// TextPropCollection tpDC = rtrD._getRawCharacterStyle(); + + // Check text and stylings +// assertEquals(trB.getRawText().substring(0, 30), rtrB.getRawText()); +// assertNotNull(tpBP); +// assertNotNull(tpBC); +// assertNotNull(tpCP); +// assertNotNull(tpCC); +// assertNotNull(tpDP); +// assertNotNull(tpDC); +// assertTrue(tpBP.equals(tpCP)); +// assertTrue(tpBP.equals(tpDP)); +// assertTrue(tpCP.equals(tpDP)); +// assertFalse(tpBC.equals(tpCC)); +// assertFalse(tpBC.equals(tpDC)); +// assertFalse(tpCC.equals(tpDC)); + + // Check text in the rich runs + assertEquals("This is the subtitle, in bold\n", rtrB.getRawText()); + assertEquals("This bit is blue and italic\n", rtrC.getRawText()); + assertEquals("This bit is red (normal)", rtrD.getRawText()); + + String newBText = "New Subtitle, will still be bold\n"; + String newCText = "New blue and italic text\n"; + String newDText = "Funky new normal red text"; + rtrB.setText(newBText); + rtrC.setText(newCText); + rtrD.setText(newDText); + assertEquals(newBText, rtrB.getRawText()); + assertEquals(newCText, rtrC.getRawText()); + assertEquals(newDText, rtrD.getRawText()); + +// assertEquals(newBText + newCText + newDText, trB.getRawText()); + + // The styles should have been updated for the new sizes +// assertEquals(newBText.length(), tpBC.getCharactersCovered()); +// assertEquals(newCText.length(), tpCC.getCharactersCovered()); +// assertEquals(newDText.length()+1, tpDC.getCharactersCovered()); // Last one is always one larger + +// assertEquals( +// newBText.length() + newCText.length() + newDText.length(), +// tpBP.getCharactersCovered() +// ); + + // Paragraph style should be sum of text length +// assertEquals(newBText.length() + newCText.length() + newDText.length(), tpBP.getCharactersCovered()); + + // Check stylings still as expected +// TextPropCollection ntpBC = rtrB._getRawCharacterStyle(); +// TextPropCollection ntpCC = rtrC._getRawCharacterStyle(); +// TextPropCollection ntpDC = rtrD._getRawCharacterStyle(); +// assertEquals(tpBC.getTextPropList(), ntpBC.getTextPropList()); +// assertEquals(tpCC.getTextPropList(), ntpCC.getTextPropList()); +// assertEquals(tpDC.getTextPropList(), ntpDC.getTextPropList()); + } + + + /** + * Test case for Bug 41015. + * + * In some cases RichTextRun.getText() threw StringIndexOutOfBoundsException because + * of the wrong list of potential paragraph properties defined in StyleTextPropAtom. + * + */ + @Test + public void testBug41015() throws IOException { + List rt; + + HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("bug-41015.ppt")); + HSLFSlide sl = ppt.getSlides().get(0); + List txt = sl.getTextParagraphs(); + assertEquals(2, txt.size()); + + rt = txt.get(0).getTextRuns(); + assertEquals(1, rt.size()); + assertEquals(0, txt.get(0).getIndentLevel()); + assertEquals("sdfsdfsdf", rt.get(0).getRawText()); + + rt = txt.get(1).getTextRuns(); + assertEquals(2, rt.size()); + assertEquals(0, txt.get(0).getIndentLevel()); + assertEquals("Sdfsdfsdf\n" + + "Dfgdfg\n" + + "Dfgdfgdfg\n", rt.get(0).getRawText()); + assertEquals(1, txt.get(1).getIndentLevel()); + assertEquals("Sdfsdfs\n" + + "Sdfsdf\n", rt.get(1).getRawText()); + } + + /** + * Test creation of TextRun objects. + */ + @Test + public void testAddTextRun() { + HSLFSlideShow ppt = new HSLFSlideShow(); + HSLFSlide slide = ppt.createSlide(); + + assertNull(slide.getTextParagraphs()); + + HSLFTextBox shape1 = new HSLFTextBox(); +// HSLFTextParagraph run1 = shape1.getTextParagraphs(); +// assertSame(run1, shape1.createTextRun()); +// run1.setText("Text 1"); + slide.addShape(shape1); + + //The array of Slide's text runs must be updated when new text shapes are added. +// HSLFTextParagraph[] runs = slide.getTextParagraphs(); +// assertNotNull(runs); +// assertSame(run1, runs.get(0)); +// +// HSLFTextBox shape2 = new HSLFTextBox(); +// HSLFTextParagraph run2 = shape2.getTextParagraphs(); +// assertSame(run2, shape2.createTextRun()); +// run2.setText("Text 2"); +// slide.addShape(shape2); +// +// runs = slide.getTextParagraphs(); +// assertEquals(2, runs.length); +// +// assertSame(run1, runs.get(0)); +// assertSame(run2, runs.get(1)); +// +// //as getShapes() +// HSLFShape[] sh = slide.getShapes(); +// assertEquals(2, sh.length); +// assertTrue(sh.get(0) instanceof HSLFTextBox); +// HSLFTextBox box1 = (HSLFTextBox)sh.get(0); +// assertSame(run1, box1.getTextParagraphs()); +// HSLFTextBox box2 = (HSLFTextBox)sh.get(1); +// assertSame(run2, box2.getTextParagraphs()); +// +// //test Table - a complex group of shapes containing text objects +// HSLFSlide slide2 = ppt.createSlide(); +// assertNull(slide2.getTextParagraphs()); +// Table table = new Table(2, 2); +// slide2.addShape(table); +// runs = slide2.getTextParagraphs(); +// assertNotNull(runs); +// assertEquals(4, runs.length); + } + + @Test + public void test48916() throws IOException { +// HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("SampleShow.ppt")); +// for(HSLFSlide slide : ppt.getSlides()){ +// for(HSLFShape sh : slide.getShapes()){ +// if(sh instanceof HSLFTextShape){ +// HSLFTextShape tx = (HSLFTextShape)sh; +// HSLFTextParagraph run = tx.getTextParagraphs(); +// //verify that records cached in TextRun and EscherTextboxWrapper are the same +// Record[] runChildren = run.getRecords(); +// Record[] txboxChildren = tx.getEscherTextboxWrapper().getChildRecords(); +// assertEquals(runChildren.length, txboxChildren.length); +// for(int i=0; i < txboxChildren.length; i++){ +// assertSame(txboxChildren.get(i), runChildren.get(i)); +// } +// //caused NPE prior to fix of Bugzilla #48916 +// run.getTextRuns().get(0).setBold(true); +// run.getTextRuns().get(0).setFontColor(Color.RED); +// } +// } +// } +// ByteArrayOutputStream out = new ByteArrayOutputStream(); +// ppt.write(out); +// ppt = new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())); +// for(HSLFSlide slide : ppt.getSlides()){ +// for(HSLFShape sh : slide.getShapes()){ +// if(sh instanceof HSLFTextShape){ +// HSLFTextShape tx = (HSLFTextShape)sh; +// HSLFTextParagraph run = tx.getTextParagraphs(); +// HSLFTextRun rt = run.getTextRuns().get(0); +// assertTrue(rt.isBold()); +// assertEquals(rt.getFontColor(), Color.RED); +// } +// } +// } + + } + + @Test + public void test52244() throws IOException { + HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("52244.ppt")); + HSLFSlide slide = ppt.getSlides().get(0); + List runs = slide.getTextParagraphs(); + + assertEquals("Arial", runs.get(0).getTextRuns().get(0).getFontFamily()); + assertEquals(36, runs.get(0).getTextRuns().get(0).getFontSize(), 0); + + assertEquals("Arial", runs.get(1).getTextRuns().get(0).getFontFamily()); + assertEquals(24, runs.get(1).getTextRuns().get(0).getFontSize(), 0); + + assertEquals("Arial", runs.get(2).getTextRuns().get(0).getFontFamily()); + assertEquals(32, runs.get(2).getTextRuns().get(0).getFontSize(), 0); + + } + +}