git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1906248 13f79535-47bb-0310-9956-ffa450edef68tags/REL_5_2_4
import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException; | import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | import org.apache.poi.openxml4j.opc.PackagePart; | ||||
import org.apache.poi.sl.draw.DrawPaint; | import org.apache.poi.sl.draw.DrawPaint; | ||||
import org.apache.poi.sl.usermodel.HighlightColorSupport; | |||||
import org.apache.poi.sl.usermodel.PaintStyle; | import org.apache.poi.sl.usermodel.PaintStyle; | ||||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; | ||||
import org.apache.poi.sl.usermodel.TextRun; | import org.apache.poi.sl.usermodel.TextRun; | ||||
import org.apache.poi.xslf.model.CharacterPropertyFetcher.CharPropFetcher; | import org.apache.poi.xslf.model.CharacterPropertyFetcher.CharPropFetcher; | ||||
import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; | import org.apache.poi.xslf.usermodel.XSLFPropertiesDelegate.XSLFFillProperties; | ||||
import org.apache.xmlbeans.XmlObject; | import org.apache.xmlbeans.XmlObject; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontCollection; | import org.openxmlformats.schemas.drawingml.x2006.main.CTFontCollection; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTFontScheme; | import org.openxmlformats.schemas.drawingml.x2006.main.CTFontScheme; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink; | import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; | import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; | import org.openxmlformats.schemas.drawingml.x2006.main.CTSolidColorFillProperties; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextStrikeType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; | import org.openxmlformats.schemas.drawingml.x2006.main.STTextUnderlineType; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.impl.CTSRgbColorImpl; | |||||
/** | /** | ||||
* Represents a run of text within the containing text body. The run element is the | * Represents a run of text within the containing text body. The run element is the | ||||
* lowest level text separation mechanism within a text body. | * lowest level text separation mechanism within a text body. | ||||
*/ | */ | ||||
@Beta | @Beta | ||||
public class XSLFTextRun implements TextRun { | |||||
public class XSLFTextRun implements TextRun, HighlightColorSupport { | |||||
private static final Logger LOG = LogManager.getLogger(XSLFTextRun.class); | private static final Logger LOG = LogManager.getLogger(XSLFTextRun.class); | ||||
private final XmlObject _r; | private final XmlObject _r; | ||||
} | } | ||||
/** | |||||
* Returns the font highlight (background) color for this text run. | |||||
* This returns a {@link SolidPaint}, or null if no highlight is set. | |||||
* | |||||
* @return The font highlight (background) colour associated with the run, null if no highlight. | |||||
* | |||||
* @see org.apache.poi.sl.draw.DrawPaint#getPaint(java.awt.Graphics2D, PaintStyle) | |||||
* @see SolidPaint#getSolidColor() | |||||
* @since POI 5.2.4 | |||||
*/ | |||||
@Override | |||||
public PaintStyle getHighlightColor() { | |||||
XSLFShape shape = getParagraph().getParentShape(); | |||||
final boolean hasPlaceholder = shape.getPlaceholder() != null; | |||||
return fetchCharacterProperty((props, highlightColor) -> fetchHighlightColor(props, highlightColor, shape, hasPlaceholder)); | |||||
} | |||||
private static void fetchHighlightColor(CTTextCharacterProperties props, Consumer<PaintStyle> highlightColor, XSLFShape shape, boolean hasPlaceholder) { | |||||
if (props == null) { | |||||
return; | |||||
} | |||||
final CTColor col = props.getHighlight(); | |||||
if (col == null) { | |||||
return; | |||||
} | |||||
final CTSRgbColor rgbCol = col.getSrgbClr(); | |||||
final byte[] cols = rgbCol.getVal(); | |||||
final SolidPaint paint = DrawPaint.createSolidPaint(new Color(0xFF & cols[0], 0xFF & cols[1], 0xFF & cols[2])); | |||||
highlightColor.accept(paint); | |||||
} | |||||
/** | |||||
* Sets the font highlight (background) color for this text run - convenience function | |||||
* | |||||
* @param color The highlight (background) color to set. | |||||
* @since POI 5.2.4 | |||||
*/ | |||||
@Override | |||||
public void setHighlightColor(final Color color) { | |||||
setHighlightColor(DrawPaint.createSolidPaint(color)); | |||||
} | |||||
/** | |||||
* Set the highlight (background) color for this text run. | |||||
* | |||||
* @param color The highlight (background) color to set. | |||||
* @throws IllegalArgumentException If the supplied paint style is not null or a SolidPaint. | |||||
* | |||||
* @see org.apache.poi.sl.draw.DrawPaint#createSolidPaint(Color) | |||||
* @since POI 5.2.4 | |||||
*/ | |||||
@Override | |||||
public void setHighlightColor(final PaintStyle color) { | |||||
if (color == null) { | |||||
final CTTextCharacterProperties rPr = getRPr(true); | |||||
if (rPr.isSetHighlight()) { | |||||
rPr.unsetHighlight(); | |||||
} | |||||
return; | |||||
} | |||||
if (!(color instanceof SolidPaint)) { | |||||
throw new IllegalArgumentException("Currently only SolidPaint is supported!"); | |||||
} | |||||
final SolidPaint sp = (SolidPaint)color; | |||||
final Color c = DrawPaint.applyColorTransform(sp.getSolidColor()); | |||||
final CTTextCharacterProperties rPr = getRPr(true); | |||||
final CTColor highlight = rPr.isSetHighlight() ? rPr.getHighlight() : rPr.addNewHighlight(); | |||||
final CTSRgbColor col = CTSRgbColor.Factory.newInstance(); | |||||
col.setVal(new byte[] {(byte)c.getRed(), (byte)c.getGreen(), (byte)c.getBlue()}); | |||||
highlight.setSrgbClr(col); | |||||
} | |||||
@Override | @Override | ||||
public void setFontSize(Double fontSize){ | public void setFontSize(Double fontSize){ |
import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor; | import static org.apache.poi.sl.usermodel.BaseTestSlideShow.getColor; | ||||
import static org.junit.jupiter.api.Assertions.assertEquals; | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
import static org.junit.jupiter.api.Assertions.assertFalse; | import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
import static org.junit.jupiter.api.Assertions.assertNotNull; | |||||
import static org.junit.jupiter.api.Assertions.assertNull; | import static org.junit.jupiter.api.Assertions.assertNull; | ||||
import static org.junit.jupiter.api.Assertions.assertThrows; | import static org.junit.jupiter.api.Assertions.assertThrows; | ||||
import static org.junit.jupiter.api.Assertions.assertTrue; | import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.awt.Graphics2D; | import java.awt.Graphics2D; | ||||
import java.awt.font.TextAttribute; | |||||
import java.awt.geom.Rectangle2D; | import java.awt.geom.Rectangle2D; | ||||
import java.awt.image.BufferedImage; | import java.awt.image.BufferedImage; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.text.AttributedCharacterIterator; | |||||
import java.text.CharacterIterator; | |||||
import java.util.List; | import java.util.List; | ||||
import java.util.Map; | |||||
import org.apache.commons.io.output.NullPrintStream; | |||||
import org.apache.poi.sl.draw.DrawTextFragment; | import org.apache.poi.sl.draw.DrawTextFragment; | ||||
import org.apache.poi.sl.draw.DrawTextParagraph; | import org.apache.poi.sl.draw.DrawTextParagraph; | ||||
import org.apache.poi.sl.usermodel.AutoNumberingScheme; | import org.apache.poi.sl.usermodel.AutoNumberingScheme; | ||||
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; | import org.apache.poi.sl.usermodel.TextParagraph.TextAlign; | ||||
import org.apache.poi.xslf.XSLFTestDataSamples; | import org.apache.poi.xslf.XSLFTestDataSamples; | ||||
import org.apache.poi.xslf.util.DummyGraphics2d; | |||||
import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||
class TestXSLFTextParagraph { | class TestXSLFTextParagraph { | ||||
assertThrows(IllegalStateException.class, () -> r2.setText("aaa")); | assertThrows(IllegalStateException.class, () -> r2.setText("aaa")); | ||||
} | } | ||||
} | } | ||||
@Test | |||||
void testHighlightRender() throws IOException { | |||||
try (XMLSlideShow ppt = new XMLSlideShow()) { | |||||
XSLFSlide slide = ppt.createSlide(); | |||||
XSLFTextShape sh = slide.createAutoShape(); | |||||
XSLFTextParagraph p = sh.addNewTextParagraph(); | |||||
XSLFTextRun r1 = p.addNewTextRun(); | |||||
r1.setText("This is a "); | |||||
XSLFTextRun r2 = p.addNewTextRun(); | |||||
r2.setText("highlight"); | |||||
r2.setHighlightColor(Color.yellow); | |||||
XSLFTextRun r3 = p.addNewTextRun(); | |||||
r3.setText(" test"); | |||||
assertEquals("This is a highlight test", sh.getText()); | |||||
DummyGraphics2d dgfx = new DummyGraphics2d(new NullPrintStream()) { | |||||
@Override | |||||
public void drawString(AttributedCharacterIterator iterator, float x, float y) { | |||||
// For the test file, common sl draws textruns one by one and not mixed | |||||
// so we evaluate the whole iterator | |||||
Map<AttributedCharacterIterator.Attribute, Object> attributes = null; | |||||
StringBuilder sb = new StringBuilder(); | |||||
for (char c = iterator.first(); | |||||
c != CharacterIterator.DONE; | |||||
c = iterator.next()) { | |||||
sb.append(c); | |||||
attributes = iterator.getAttributes(); | |||||
} | |||||
if ("This is a".equals(sb.toString())) { | |||||
// Should be no background. | |||||
assertNotNull(attributes); | |||||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||||
assertNull(background); | |||||
} | |||||
if ("highlight".equals(sb.toString())) { | |||||
// Should be yellow background. | |||||
assertNotNull(attributes); | |||||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||||
assertNotNull(background); | |||||
assertTrue(background instanceof Color); | |||||
assertEquals(Color.yellow, background); | |||||
} | |||||
if (" test".equals(sb.toString())) { | |||||
// Should be no background. | |||||
assertNotNull(attributes); | |||||
Object background = attributes.get(TextAttribute.BACKGROUND); | |||||
assertNull(background); | |||||
} | |||||
} | |||||
}; | |||||
ppt.getSlides().get(0).draw(dgfx); | |||||
} | |||||
} | |||||
} | } |
import static org.junit.jupiter.api.Assertions.assertEquals; | import static org.junit.jupiter.api.Assertions.assertEquals; | ||||
import static org.junit.jupiter.api.Assertions.assertFalse; | import static org.junit.jupiter.api.Assertions.assertFalse; | ||||
import static org.junit.jupiter.api.Assertions.assertNotEquals; | import static org.junit.jupiter.api.Assertions.assertNotEquals; | ||||
import static org.junit.jupiter.api.Assertions.assertNull; | |||||
import static org.junit.jupiter.api.Assertions.assertTrue; | import static org.junit.jupiter.api.Assertions.assertTrue; | ||||
import static org.junit.jupiter.api.Assertions.fail; | |||||
import java.awt.Color; | import java.awt.Color; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import org.apache.poi.POIDataSamples; | import org.apache.poi.POIDataSamples; | ||||
import org.apache.poi.openxml4j.opc.PackagePart; | |||||
import org.apache.poi.sl.draw.DrawPaint; | |||||
import org.apache.poi.sl.draw.DrawTextParagraph; | import org.apache.poi.sl.draw.DrawTextParagraph; | ||||
import org.apache.poi.sl.usermodel.PaintStyle; | |||||
import org.apache.poi.xslf.model.PropertyFetcher; | |||||
import org.junit.jupiter.api.Test; | import org.junit.jupiter.api.Test; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTGradientFillProperties; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSchemeColor; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeStyle; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTStyleMatrixReference; | |||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak; | ||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; | import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph; | ||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | import org.openxmlformats.schemas.presentationml.x2006.main.CTShape; | ||||
r.setSubscript(false); | r.setSubscript(false); | ||||
assertFalse(r.isSubscript()); | assertFalse(r.isSubscript()); | ||||
// Test highlight get/set. | |||||
assertNull(r.getHighlightColor()); | |||||
r.setHighlightColor(Color.yellow); | |||||
assertEquals(DrawPaint.createSolidPaint(Color.yellow), r.getHighlightColor()); | |||||
r.setHighlightColor(DrawPaint.createSolidPaint(Color.blue)); | |||||
assertEquals(DrawPaint.createSolidPaint(Color.blue), r.getHighlightColor()); | |||||
r.setHighlightColor((Color) null); | |||||
assertNull(r.getHighlightColor()); | |||||
r.setHighlightColor((PaintStyle) null); | |||||
assertNull(r.getHighlightColor()); | |||||
try { | |||||
// make a dummy gradient to test paint rejection. | |||||
final XSLFSheet sheet = sh.getSheet(); | |||||
final XSLFTheme theme = sheet.getTheme(); | |||||
final CTSchemeColor phClr = CTSchemeColor.Factory.newInstance(); | |||||
final CTGradientFillProperties gradFill = CTGradientFillProperties.Factory.newInstance(); | |||||
final XSLFGradientPaint dummyGrad = new XSLFGradientPaint(gradFill, phClr, theme, sheet); | |||||
r.setHighlightColor(dummyGrad); | |||||
fail("Expected non solid paint to cause an exception."); | |||||
} catch (IllegalArgumentException iae) { | |||||
// Expected, do nothing. | |||||
} | |||||
ppt.close(); | ppt.close(); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
@Test | @Test | ||||
void testAppendEmpty() throws IOException { | void testAppendEmpty() throws IOException { | ||||
try (HSLFSlideShow ppt = new HSLFSlideShow()) { | try (HSLFSlideShow ppt = new HSLFSlideShow()) { |
import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange; | import org.apache.poi.common.usermodel.fonts.FontGroup.FontGroupRange; | ||||
import org.apache.poi.common.usermodel.fonts.FontInfo; | import org.apache.poi.common.usermodel.fonts.FontInfo; | ||||
import org.apache.poi.sl.usermodel.AutoNumberingScheme; | import org.apache.poi.sl.usermodel.AutoNumberingScheme; | ||||
import org.apache.poi.sl.usermodel.HighlightColorSupport; | |||||
import org.apache.poi.sl.usermodel.Hyperlink; | import org.apache.poi.sl.usermodel.Hyperlink; | ||||
import org.apache.poi.sl.usermodel.Insets2D; | import org.apache.poi.sl.usermodel.Insets2D; | ||||
import org.apache.poi.sl.usermodel.PaintStyle; | import org.apache.poi.sl.usermodel.PaintStyle; | ||||
import org.apache.poi.util.LocaleUtil; | import org.apache.poi.util.LocaleUtil; | ||||
import org.apache.poi.util.StringUtil; | import org.apache.poi.util.StringUtil; | ||||
import org.apache.poi.util.Units; | import org.apache.poi.util.Units; | ||||
import org.w3c.dom.Text; | |||||
public class DrawTextParagraph implements Drawable { | public class DrawTextParagraph implements Drawable { | ||||
private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class); | private static final Logger LOG = LogManager.getLogger(DrawTextParagraph.class); | ||||
att.put(TextAttribute.FOREGROUND, fgPaint); | att.put(TextAttribute.FOREGROUND, fgPaint); | ||||
if (run instanceof HighlightColorSupport) { | |||||
// Highlight color is only supported in XSLF (PPTX) text runs. | |||||
final PaintStyle highlightPaintStyle = ((HighlightColorSupport)run).getHighlightColor(); | |||||
if (highlightPaintStyle != null) { | |||||
final Paint bgPaint = dp.getPaint(graphics, highlightPaintStyle); | |||||
att.put(TextAttribute.BACKGROUND, bgPaint); | |||||
} | |||||
} | |||||
Double fontSz = run.getFontSize(); | Double fontSz = run.getFontSize(); | ||||
if (fontSz == null) { | if (fontSz == null) { | ||||
fontSz = paragraph.getDefaultFontSize(); | fontSz = paragraph.getDefaultFontSize(); |
*/ | */ | ||||
@SuppressWarnings({"unused","java:S1452"}) | @SuppressWarnings({"unused","java:S1452"}) | ||||
public interface TextRun { | public interface TextRun { | ||||
/** | /** | ||||
* Type of text capitals | * Type of text capitals | ||||
*/ | */ | ||||
*/ | */ | ||||
void setFontColor(PaintStyle color); | void setFontColor(PaintStyle color); | ||||
/** | /** | ||||
* Returns the font size which is either set directly on this text run or | * Returns the font size which is either set directly on this text run or | ||||
* given from the slide layout | * given from the slide layout |