/* ==================================================================== | |
Licensed to the Apache Software Foundation (ASF) under one or more | |
contributor license agreements. See the NOTICE file distributed with | |
this work for additional information regarding copyright ownership. | |
The ASF licenses this file to You under the Apache License, Version 2.0 | |
(the "License"); you may not use this file except in compliance with | |
the License. You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
==================================================================== */ | |
package org.apache.poi.xslf.usermodel; | |
import static org.apache.poi.sl.TestCommonSL.sameColor; | |
import static org.junit.Assert.assertEquals; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertNull; | |
import static org.junit.Assert.assertTrue; | |
import java.awt.Color; | |
import java.awt.Graphics2D; | |
import java.awt.geom.Rectangle2D; | |
import java.awt.image.BufferedImage; | |
import java.io.IOException; | |
import java.util.List; | |
import org.apache.poi.sl.draw.DrawTextFragment; | |
import org.apache.poi.sl.draw.DrawTextParagraph; | |
import org.apache.poi.sl.usermodel.AutoNumberingScheme; | |
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; | |
import org.apache.poi.xslf.XSLFTestDataSamples; | |
import org.junit.Assume; | |
import org.junit.Test; | |
/** | |
* @author Yegor Kozlov | |
*/ | |
public class TestXSLFTextParagraph { | |
// private static POILogger _logger = POILogFactory.getLogger(XSLFTextParagraph.class); | |
static class DrawTextParagraphProxy extends DrawTextParagraph { | |
DrawTextParagraphProxy(XSLFTextParagraph p) { | |
super(p); | |
} | |
@Override | |
public void breakText(Graphics2D graphics) { | |
super.breakText(graphics); | |
} | |
@Override | |
public double getWrappingWidth(boolean firstLine, Graphics2D graphics) { | |
return super.getWrappingWidth(firstLine, graphics); | |
} | |
public List<DrawTextFragment> getLines() { | |
return lines; | |
} | |
} | |
@Test | |
public void testWrappingWidth() throws IOException { | |
XMLSlideShow ppt = new XMLSlideShow(); | |
XSLFSlide slide = ppt.createSlide(); | |
XSLFTextShape sh = slide.createAutoShape(); | |
sh.setLineColor(Color.black); | |
XSLFTextParagraph p = sh.addNewTextParagraph(); | |
p.addNewTextRun().setText( | |
"Paragraph formatting allows for more granular control " + | |
"of text within a shape. Properties here apply to all text " + | |
"residing within the corresponding paragraph."); | |
Rectangle2D anchor = new Rectangle2D.Double(50, 50, 300, 200); | |
sh.setAnchor(anchor); | |
DrawTextParagraphProxy dtp = new DrawTextParagraphProxy(p); | |
Double leftInset = sh.getLeftInset(); | |
Double rightInset = sh.getRightInset(); | |
assertEquals(7.2, leftInset, 0); | |
assertEquals(7.2, rightInset, 0); | |
Double leftMargin = p.getLeftMargin(); | |
assertEquals(0.0, leftMargin, 0); | |
Double indent = p.getIndent(); | |
assertNull(indent); // default | |
double expectedWidth; | |
// Case 1: bullet=false, leftMargin=0, indent=0. | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |
assertEquals(285.6, expectedWidth, 0); // 300 - 7.2 - 7.2 - 0 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0); | |
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); | |
p.setLeftMargin(36d); // 0.5" | |
leftMargin = p.getLeftMargin(); | |
assertEquals(36.0, leftMargin, 0); | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |
assertEquals(249.6, expectedWidth, 1E-5); // 300 - 7.2 - 7.2 - 36 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0); | |
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); | |
// increase insets, the wrapping width should get smaller | |
sh.setLeftInset(10); | |
sh.setRightInset(10); | |
leftInset = sh.getLeftInset(); | |
rightInset = sh.getRightInset(); | |
assertEquals(10.0, leftInset, 0); | |
assertEquals(10.0, rightInset, 0); | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |
assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0); | |
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); | |
// set a positive indent of a 0.5 inch. This means "First Line" indentation: | |
// |<--- indent -->|Here goes first line of the text | |
// Here go other lines (second and subsequent) | |
p.setIndent(36.0); // 0.5" | |
indent = p.getIndent(); | |
assertEquals(36.0, indent, 0); | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin - indent; | |
assertEquals(208.0, expectedWidth, 0); // 300 - 10 - 10 - 36 - 6.4 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0); // first line is indented | |
// other lines are not indented | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |
assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); | |
// set a negative indent of a 1 inch. This means "Hanging" indentation: | |
// Here goes first line of the text | |
// |<--- indent -->|Here go other lines (second and subsequent) | |
p.setIndent(-72.0); // 1" | |
indent = p.getIndent(); | |
assertEquals(-72.0, indent, 0); | |
expectedWidth = anchor.getWidth() - leftInset - rightInset; | |
assertEquals(280.0, expectedWidth, 0); // 300 - 10 - 10 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(true, null), 0); // first line is NOT indented | |
// other lines are indented by leftMargin (the value of indent is not used) | |
expectedWidth = anchor.getWidth() - leftInset - rightInset - leftMargin; | |
assertEquals(244.0, expectedWidth, 0); // 300 - 10 - 10 - 36 | |
assertEquals(expectedWidth, dtp.getWrappingWidth(false, null), 0); | |
ppt.close(); | |
} | |
/** | |
* test breaking test into lines. | |
* This test requires that the Arial font is available and will run only on windows | |
*/ | |
@Test | |
public void testBreakLines() throws IOException { | |
String os = System.getProperty("os.name"); | |
Assume.assumeTrue("Skipping testBreakLines(), it is executed only on Windows machines", (os != null && os.contains("Windows"))); | |
XMLSlideShow ppt = new XMLSlideShow(); | |
XSLFSlide slide = ppt.createSlide(); | |
XSLFTextShape sh = slide.createAutoShape(); | |
XSLFTextParagraph p = sh.addNewTextParagraph(); | |
XSLFTextRun r = p.addNewTextRun(); | |
r.setFontFamily("Arial"); // this should always be available | |
r.setFontSize(12d); | |
r.setText( | |
"Paragraph formatting allows for more granular control " + | |
"of text within a shape. Properties here apply to all text " + | |
"residing within the corresponding paragraph."); | |
sh.setAnchor(new Rectangle2D.Double(50, 50, 300, 200)); | |
DrawTextParagraphProxy dtp = new DrawTextParagraphProxy(p); | |
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); | |
Graphics2D graphics = img.createGraphics(); | |
List<DrawTextFragment> lines; | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(4, lines.size()); | |
// decrease the shape width from 300 pt to 100 pt | |
sh.setAnchor(new Rectangle2D.Double(50, 50, 100, 200)); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(12, lines.size()); | |
// decrease the shape width from 300 pt to 100 pt | |
sh.setAnchor(new Rectangle2D.Double(50, 50, 600, 200)); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(2, lines.size()); | |
// set left and right margins to 200pt. This leaves 200pt for wrapping text | |
sh.setLeftInset(200); | |
sh.setRightInset(200); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(5, lines.size()); | |
r.setText("Apache POI"); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(1, lines.size()); | |
assertEquals("Apache POI", lines.get(0).getString()); | |
r.setText("Apache\nPOI"); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(2, lines.size()); | |
assertEquals("Apache", lines.get(0).getString()); | |
assertEquals("POI", lines.get(1).getString()); | |
// trailing newlines are ignored | |
r.setText("Apache\nPOI\n"); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(2, lines.size()); | |
assertEquals("Apache", lines.get(0).getString()); | |
assertEquals("POI", lines.get(1).getString()); | |
XSLFAutoShape sh2 = slide.createAutoShape(); | |
sh2.setAnchor(new Rectangle2D.Double(50, 50, 300, 200)); | |
XSLFTextParagraph p2 = sh2.addNewTextParagraph(); | |
XSLFTextRun r2 = p2.addNewTextRun(); | |
r2.setFontFamily("serif"); // this should always be available | |
r2.setFontSize(30d); | |
r2.setText("Apache\n"); | |
XSLFTextRun r3 = p2.addNewTextRun(); | |
r3.setFontFamily("serif"); // this should always be available | |
r3.setFontSize(10d); | |
r3.setText("POI"); | |
dtp = new DrawTextParagraphProxy(p2); | |
dtp.breakText(graphics); | |
lines = dtp.getLines(); | |
assertEquals(2, lines.size()); | |
assertEquals("Apache", lines.get(0).getString()); | |
assertEquals("POI", lines.get(1).getString()); | |
// the first line is at least two times higher than the second | |
assertTrue(lines.get(0).getHeight() > lines.get(1).getHeight()*2); | |
ppt.close(); | |
} | |
@Test | |
public void testThemeInheritance() throws IOException { | |
XMLSlideShow ppt = XSLFTestDataSamples.openSampleDocument("prProps.pptx"); | |
List<XSLFShape> 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.get(1); | |
assertEquals("Software", sh2.getText()); | |
assertEquals(TextAlign.CENTER, sh2.getTextParagraphs().get(0).getTextAlign()); | |
XSLFTextShape sh3 = (XSLFTextShape)shapes.get(2); | |
assertEquals("Foundation", sh3.getText()); | |
assertEquals(TextAlign.CENTER, sh3.getTextParagraphs().get(0).getTextAlign()); | |
ppt.close(); | |
} | |
@Test | |
public void testParagraphProperties() throws IOException { | |
XMLSlideShow ppt = new XMLSlideShow(); | |
XSLFSlide slide = ppt.createSlide(); | |
XSLFTextShape sh = slide.createAutoShape(); | |
XSLFTextParagraph p = sh.addNewTextParagraph(); | |
assertFalse(p.isBullet()); | |
p.setBullet(true); | |
assertTrue(p.isBullet()); | |
assertEquals("\u2022", p.getBulletCharacter()); | |
p.setBulletCharacter("*"); | |
assertEquals("*", p.getBulletCharacter()); | |
assertEquals("Arial", p.getBulletFont()); | |
p.setBulletFont("Calibri"); | |
assertEquals("Calibri", p.getBulletFont()); | |
assertEquals(null, p.getBulletFontColor()); | |
p.setBulletFontColor(Color.red); | |
assertTrue(sameColor(Color.red, p.getBulletFontColor())); | |
assertNull(p.getBulletFontSize()); | |
p.setBulletFontSize(200.); | |
assertEquals(200., p.getBulletFontSize(), 0); | |
p.setBulletFontSize(-20.); | |
assertEquals(-20.0, p.getBulletFontSize(), 0); | |
assertEquals(72.0, p.getDefaultTabSize(), 0); | |
assertNull(p.getIndent()); | |
p.setIndent(72.0); | |
assertEquals(72.0, p.getIndent(), 0); | |
p.setIndent(-1d); // the value of -1.0 resets to the defaults (not any more ...) | |
assertEquals(-1d, p.getIndent(), 0); | |
p.setIndent(null); | |
assertNull(p.getIndent()); | |
assertEquals(0.0, p.getLeftMargin(), 0); | |
p.setLeftMargin(72.0); | |
assertEquals(72.0, p.getLeftMargin(), 0); | |
p.setLeftMargin(-1.0); // the value of -1.0 resets to the defaults | |
assertEquals(-1.0, p.getLeftMargin(), 0); | |
p.setLeftMargin(null); | |
assertEquals(0d, p.getLeftMargin(), 0); // default will be taken from master | |
assertEquals(0, p.getIndentLevel()); | |
p.setIndentLevel(1); | |
assertEquals(1, p.getIndentLevel()); | |
p.setIndentLevel(2); | |
assertEquals(2, p.getIndentLevel()); | |
assertNull(p.getLineSpacing()); | |
p.setLineSpacing(200.); | |
assertEquals(200.0, p.getLineSpacing(), 0); | |
p.setLineSpacing(-15.); | |
assertEquals(-15.0, p.getLineSpacing(), 0); | |
assertNull(p.getSpaceAfter()); | |
p.setSpaceAfter(200.); | |
assertEquals(200.0, p.getSpaceAfter(), 0); | |
p.setSpaceAfter(-15.); | |
assertEquals(-15.0, p.getSpaceAfter(), 0); | |
p.setSpaceAfter(null); | |
assertNull(p.getSpaceAfter()); | |
p.setSpaceAfter(null); | |
assertNull(p.getSpaceAfter()); | |
assertNull(p.getSpaceBefore()); | |
p.setSpaceBefore(200.); | |
assertEquals(200.0, p.getSpaceBefore(), 0); | |
p.setSpaceBefore(-15.); | |
assertEquals(-15.0, p.getSpaceBefore(), 0); | |
p.setSpaceBefore(null); | |
assertNull(p.getSpaceBefore()); | |
p.setSpaceBefore(null); | |
assertNull(p.getSpaceBefore()); | |
assertEquals(TextAlign.LEFT, p.getTextAlign()); | |
p.setTextAlign(TextAlign.RIGHT); | |
assertEquals(TextAlign.RIGHT, p.getTextAlign()); | |
p.setBullet(false); | |
assertFalse(p.isBullet()); | |
p.setBulletAutoNumber(AutoNumberingScheme.alphaLcParenBoth, 1); | |
double tabStop = p.getTabStop(0); | |
assertEquals(0.0, tabStop, 0); | |
p.addTabStop(100.); | |
assertEquals(100., p.getTabStop(0), 0); | |
assertEquals(72.0, p.getDefaultTabSize(), 0); | |
ppt.close(); | |
} | |
@Test(expected = IllegalStateException.class) | |
public void testLineBreak() throws IOException { | |
XMLSlideShow ppt = new XMLSlideShow(); | |
try { | |
XSLFSlide slide = ppt.createSlide(); | |
XSLFTextShape sh = slide.createAutoShape(); | |
XSLFTextParagraph p = sh.addNewTextParagraph(); | |
XSLFTextRun r1 = p.addNewTextRun(); | |
r1.setText("Hello,"); | |
XSLFTextRun r2 = p.addLineBreak(); | |
assertEquals("\n", r2.getRawText()); | |
r2.setFontSize(10.0); | |
assertEquals(10.0, r2.getFontSize(), 0); | |
XSLFTextRun r3 = p.addNewTextRun(); | |
r3.setText("World!"); | |
r3.setFontSize(20.0); | |
XSLFTextRun r4 = p.addLineBreak(); | |
assertEquals(20.0, r4.getFontSize(), 0); | |
assertEquals("Hello,\nWorld!\n",sh.getText()); | |
// "You cannot change text of a line break, it is always '\\n'" | |
r2.setText("aaa"); | |
} finally { | |
ppt.close(); | |
} | |
} | |
} |