From: Yegor Kozlov Date: Mon, 28 May 2007 09:45:09 +0000 (+0000) Subject: support for text bullets X-Git-Tag: REL_3_0_1_RC1~14 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ff60d78860a922c1fbf796cf6373414f8a03503e;p=poi.git support for text bullets git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@542179 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/hslf/how-to-shapes.xml b/src/documentation/content/xdocs/hslf/how-to-shapes.xml index fd3d6c3bb6..74e921f8fe 100644 --- a/src/documentation/content/xdocs/hslf/how-to-shapes.xml +++ b/src/documentation/content/xdocs/hslf/how-to-shapes.xml @@ -37,6 +37,7 @@
  • How to work with pictures
  • How to set slide title
  • How to work with slide/shape background
  • +
  • How to create bulleted lists
  • Features @@ -319,6 +320,35 @@ slide.addShape(shape);
    + +
    How to create bulleted lists + + SlideShow ppt = new SlideShow(); + + Slide slide = ppt.createSlide(); + + TextBox shape = new TextBox(); + RichTextRun rt = shape.getTextRun().getRichTextRuns()[0]; + shape.setText( + "January\r" + + "February\r" + + "March\r" + + "April"); + rt.setFontSize(42); + rt.setBullet(true); + rt.setBulletOffset(0); //bullet offset + rt.setTextOffset(50); //text offset (should be greater than bullet offset) + rt.setBulletChar('\u263A'); //bullet character + slide.addShape(shape); + + shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300)); //position of the text box in the slide + slide.addShape(shape); + + FileOutputStream out = new FileOutputStream("bullets.ppt"); + ppt.write(out); + out.close(); + +
    diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java new file mode 100644 index 0000000000..a4559713c4 --- /dev/null +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/BulletsDemo.java @@ -0,0 +1,62 @@ + +/* ==================================================================== + 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.examples; + +import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.hslf.usermodel.RichTextRun; +import org.apache.poi.hslf.model.Slide; +import org.apache.poi.hslf.model.TextBox; + +import java.io.FileOutputStream; + +/** + * How to create a single-level bulleted list + * and change some of the bullet attributes + * + * @author Yegor Kozlov + */ +public class BulletsDemo { + + public static void main(String[] args) throws Exception { + + SlideShow ppt = new SlideShow(); + + Slide slide = ppt.createSlide(); + + TextBox shape = new TextBox(); + RichTextRun rt = shape.getTextRun().getRichTextRuns()[0]; + shape.setText( + "January\r" + + "February\r" + + "March\r" + + "April"); + rt.setFontSize(42); + rt.setBullet(true); + rt.setBulletOffset(0); //bullet offset + rt.setTextOffset(50); //text offset (should be greater than bullet offset) + rt.setBulletChar('\u263A'); //bullet character + slide.addShape(shape); + + shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300)); //position of the text box in the slide + slide.addShape(shape); + + FileOutputStream out = new FileOutputStream("bullets.ppt"); + ppt.write(out); + out.close(); + } +} diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java index 9466194a91..a78c2c27e5 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/CharFlagsTextProp.java @@ -32,8 +32,9 @@ public class CharFlagsTextProp extends BitMaskTextProp { public static final int ENABLE_NUMBERING_1_IDX = 11; public static final int ENABLE_NUMBERING_2_IDX = 12; + public static String NAME = "char_flags"; public CharFlagsTextProp() { - super(2,0xffff, "char_flags", new String[] { + super(2,0xffff, NAME, new String[] { "bold", // 0x0001 "italic", // 0x0002 "underline", // 0x0004 diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/ParagraphFlagsTextProp.java b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/ParagraphFlagsTextProp.java new file mode 100644 index 0000000000..0ea21b2992 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/textproperties/ParagraphFlagsTextProp.java @@ -0,0 +1,41 @@ +/* ==================================================================== + 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; + +/** + * Definition for the common paragraph text property bitset. + * + * @author Yegor Kozlov + */ +public class ParagraphFlagsTextProp extends BitMaskTextProp { + public static final int BULLET_IDX = 0; + public static final int BULLET_HARDFONT_IDX = 1; + public static final int BULLET_HARDCOLOR_IDX = 2; + public static final int BULLET_HARDSIZE_IDX = 4; + + public static String NAME = "paragraph_flags"; + + public ParagraphFlagsTextProp() { + super(2, 0xF, NAME, new String[] { + "bullet", + "bullet.hardfont", + "bullet.hardcolor", + "bullet.hardsize"} + ); + } +} \ No newline at end of file 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 41fbb698b6..32f8b2bd03 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java @@ -19,11 +19,7 @@ package org.apache.poi.hslf.record; -import org.apache.poi.hslf.model.textproperties.AlignmentTextProp; -import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; -import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; -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.LittleEndian; import org.apache.poi.util.POILogger; @@ -95,18 +91,15 @@ public class StyleTextPropAtom extends RecordAtom /** All the different kinds of paragraph properties we might handle */ public static TextProp[] paragraphTextPropTypes = new TextProp[] { - new BitMaskTextProp(2, 0xF, "paragraph_flags", new String[] { - "bullet", "bullet.hardfont", - "bullet.hardcolor", "bullet.hardsize"} - ), + new ParagraphFlagsTextProp(), new TextProp(2, 0x80, "bullet.char"), new TextProp(2, 0x10, "bullet.font"), new TextProp(4, 0x20, "bullet.color"), new TextProp(2, 0x40, "bullet.size"), new AlignmentTextProp(), - new TextProp(2, 0x400, "bullet.offset"), - new TextProp(2, 0x200, "para_unknown_2"), new TextProp(2, 0x100, "text.offset"), + new TextProp(2, 0x200, "para_unknown_2"), + new TextProp(2, 0x400, "bullet.offset"), new TextProp(2, 0x1000, "linespacing"), new TextProp(2, 0x2000, "spacebefore"), new TextProp(2, 0x4000, "spaceafter"), 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 12c8c1f6e2..c3025fb4be 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java +++ b/src/scratchpad/src/org/apache/poi/hslf/record/TxMasterStyleAtom.java @@ -23,10 +23,7 @@ import org.apache.poi.util.LittleEndian; import java.io.OutputStream; import java.io.IOException; -import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; -import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; +import org.apache.poi.hslf.model.textproperties.*; /** * TxMasterStyleAtom atom (4003). @@ -177,10 +174,7 @@ public class TxMasterStyleAtom extends RecordAtom { return StyleTextPropAtom.paragraphTextPropTypes; } else { return new TextProp[] { - new BitMaskTextProp(2, 0xF, "paragraph_flags", new String[] { - "bullet", "bullet.hardfont", - "bullet.hardcolor", "bullet.hardsize"} - ), + new ParagraphFlagsTextProp(), new TextProp(2, 0x80, "bullet.char"), new TextProp(2, 0x10, "bullet.font"), new TextProp(2, 0x40, "bullet.size"), diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java index a9028cfab2..0ee01b9a96 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java @@ -20,18 +20,15 @@ package org.apache.poi.hslf.usermodel; -import org.apache.poi.hslf.model.TextRun; -import org.apache.poi.hslf.model.Sheet; -import org.apache.poi.hslf.model.SlideMaster; -import org.apache.poi.hslf.model.MasterSheet; -import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp; -import org.apache.poi.hslf.model.textproperties.TextProp; -import org.apache.poi.hslf.model.textproperties.TextPropCollection; -import org.apache.poi.hslf.model.textproperties.BitMaskTextProp; +import org.apache.poi.hslf.model.*; +import org.apache.poi.hslf.model.Shape; +import org.apache.poi.hslf.model.textproperties.*; import org.apache.poi.hslf.record.ColorSchemeAtom; +import org.apache.poi.hslf.exceptions.HSLFException; import java.awt.*; + /** * Represents a run of text, all with the same style * @@ -164,36 +161,63 @@ public class RichTextRun * text property won't be set if there's no CharFlagsTextProp. */ private boolean isCharFlagsTextPropVal(int index) { - CharFlagsTextProp cftp = null; - if (characterStyle != null){ - cftp = (CharFlagsTextProp)characterStyle.findByName("char_flags"); + 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; + } + + BitMaskTextProp prop = null; + if (props != null){ + prop = (BitMaskTextProp)props.findByName(propname); } - if (cftp == null){ + if (prop == null){ Sheet sheet = parentRun.getSheet(); int txtype = parentRun.getRunType(); MasterSheet master = sheet.getMasterSheet(); if (master != null) - cftp = (CharFlagsTextProp)master.getStyleAttribute(txtype, getIndentLevel(), "char_flags", true); + prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter); } - return cftp == null ? false : cftp.getSubValue(index); - } + return prop == null ? false : prop.getSubValue(index); + } /** * Set the value of the given flag in the CharFlagsTextProp, adding * it if required. */ private void setCharFlagsTextPropVal(int index, boolean value) { + setFlag(true, index, value); + } + + private 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(characterStyle == null) { + if(props == null) { parentRun.ensureStyleAtomPresent(); - // characterStyle will now be defined + props = isCharacter ? characterStyle : paragraphStyle; } - - CharFlagsTextProp cftp = (CharFlagsTextProp) - fetchOrAddTextProp(characterStyle, "char_flags"); - cftp.setSubValue(value,index); - } + + BitMaskTextProp prop = (BitMaskTextProp) fetchOrAddTextProp(props, propname); + prop.setSubValue(value,index); + } /** * Returns the named TextProp, either by fetching it (if it exists) or adding it @@ -396,7 +420,62 @@ public class RichTextRun public int getIndentLevel() { return paragraphStyle == null ? 0 : paragraphStyle.getReservedField(); } - + + /** + * Sets whether this rich text run has bullets + */ + public void setBullet(boolean flag) { + setFlag(false, ParagraphFlagsTextProp.BULLET_IDX, flag); + } + + /** + * Returns whether this rich text run has bullets + */ + public boolean isBullet() { + 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*Shape.MASTER_DPI/Shape.POINT_DPI); + } + + /** + * Returns the bullet offset + */ + public int getBulletOffset() { + return getParaTextPropVal("bullet.offset")*Shape.POINT_DPI/Shape.MASTER_DPI; + } + + /** + * Sets the text offset + */ + public void setTextOffset(int offset) { + setParaTextPropVal("text.offset", offset*Shape.MASTER_DPI/Shape.POINT_DPI); + } + + /** + * Returns the text offset + */ + public int getTextOffset() { + return getParaTextPropVal("text.offset")*Shape.POINT_DPI/Shape.MASTER_DPI; + } // --------------- Internal HSLF methods, not intended for end-user use! ------- /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java index e77f9ff13e..4f4e9e96d8 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java @@ -119,7 +119,14 @@ public class SlideShow public SlideShow() throws IOException { this(new HSLFSlideShow()); } - + + /** + * Constructs a Powerpoint document from an input stream. + */ + public SlideShow(InputStream inputStream) throws IOException { + this(new HSLFSlideShow(inputStream)); + } + /** * Find the records that are parent-aware, and tell them * who their parent is diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/bullets.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/bullets.ppt new file mode 100644 index 0000000000..be2f8bba9f Binary files /dev/null and b/src/scratchpad/testcases/org/apache/poi/hslf/data/bullets.ppt differ diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java index 6f4e128c8b..2450c66c08 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestRichTextRun.java @@ -16,15 +16,11 @@ */ package org.apache.poi.hslf.usermodel; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FileInputStream; -import java.io.File; +import java.io.*; +import java.awt.*; import org.apache.poi.hslf.HSLFSlideShow; -import org.apache.poi.hslf.model.Slide; -import org.apache.poi.hslf.model.TextRun; -import org.apache.poi.hslf.model.SlideMaster; +import org.apache.poi.hslf.model.*; import org.apache.poi.hslf.record.Record; import org.apache.poi.hslf.record.SlideListWithText; @@ -458,4 +454,99 @@ if(false) { } } } + + public void testReadParagraphStyles() throws Exception { + FileInputStream is = new FileInputStream(new File(System.getProperty("HSLF.testdata.path"), "bullets.ppt")); + SlideShow ppt = new SlideShow(is); + is.close(); + assertTrue("No Exceptions while reading file", true); + + RichTextRun rt; + TextRun[] txt; + Slide[] slide = ppt.getSlides(); + assertEquals(2, slide.length); + + txt = slide[0].getTextRuns(); + assertEquals(2, txt.length); + + assertEquals("Title text", txt[0].getRawText()); + assertEquals(1, txt[0].getRichTextRuns().length); + rt = txt[0].getRichTextRuns()[0]; + assertFalse(rt.isBullet()); + + assertEquals( + "This is a text placeholder that \r" + + "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('\u2022', rt.getBulletChar()); + assertTrue(rt.isBullet()); + + + txt = slide[1].getTextRuns(); + assertEquals(2, txt.length); + + assertEquals( + "I’m a text box\r" + + "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]; + assertTrue(rt.isBullet()); + assertEquals('\u2022', rt.getBulletChar()); + + assertEquals( + "I’m a text box with user-defined\r" + + "bullet character", txt[1].getRawText()); + assertEquals(1, txt[1].getRichTextRuns().length); + rt = txt[1].getRichTextRuns()[0]; + assertTrue(rt.isBullet()); + assertEquals('\u263A', rt.getBulletChar()); + } + + public void testSetParagraphStyles() throws Exception { + SlideShow ppt = new SlideShow(); + + Slide slide = ppt.createSlide(); + + TextBox shape = new TextBox(); + RichTextRun rt = shape.getTextRun().getRichTextRuns()[0]; + shape.setText( + "Hello, World!\r" + + "This should be\r" + + "Multiline text"); + rt.setFontSize(42); + rt.setBullet(true); + rt.setTextOffset(50); + rt.setBulletOffset(0); + rt.setBulletChar('\u263A'); + slide.addShape(shape); + + assertEquals(42, rt.getFontSize()); + assertEquals(true, rt.isBullet()); + assertEquals(50, rt.getTextOffset()); + assertEquals(0, rt.getBulletOffset()); + assertEquals('\u263A', rt.getBulletChar()); + + shape.setAnchor(new java.awt.Rectangle(50, 50, 500, 300)); + slide.addShape(shape); + + //serialize and read again + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ppt.write(out); + out.close(); + + ppt = new SlideShow(new ByteArrayInputStream(out.toByteArray())); + slide = ppt.getSlides()[0]; + shape = (TextBox)slide.getShapes()[0]; + rt = shape.getTextRun().getRichTextRuns()[0]; + assertEquals(42, rt.getFontSize()); + assertEquals(true, rt.isBullet()); + assertEquals(50, rt.getTextOffset()); + assertEquals(0, rt.getBulletOffset()); + assertEquals('\u263A', rt.getBulletChar()); + } }