- #47904 - Update text styles in HSLF MasterSlide

- common sl unification for TextParagraph.setTextAlign

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1717351 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2015-11-30 23:34:30 +00:00
parent e772eeecde
commit f0ed3cbbab
12 changed files with 228 additions and 90 deletions

View File

@ -105,7 +105,7 @@ public final class TableDemo {
} else {
rt.getTextParagraph().setBullet(true);
rt.setFontSize(12d);
rt.getTextParagraph().setAlignment(TextAlign.LEFT);
rt.getTextParagraph().setTextAlign(TextAlign.LEFT);
cell.setHorizontalCentered(false);
}
cell.setVerticalAlignment(VerticalAlignment.MIDDLE);

View File

@ -312,11 +312,21 @@ public interface TextParagraph<
/**
* Returns the alignment that is applied to the paragraph.
*
* If this attribute is omitted, then a value of left is implied.
* @return ??? alignment that is applied to the paragraph
* If this attribute is omitted, then null is returned.
* User code can imply the value {@link org.apache.poi.sl.usermodel.TextParagraph.TextAlign#LEFT} then.
*
* @return alignment that is applied to the paragraph
*/
TextAlign getTextAlign();
/**
* Specifies the alignment that is to be applied to the paragraph.
* Possible values for this include left, right, centered, justified and distributed,
* see {@link org.apache.poi.sl.usermodel.TextParagraph.TextAlign}.
*
* @param align text align
*/
void setTextAlign(TextAlign align);
/**
* Returns the font alignment that is applied to the paragraph.

View File

@ -163,14 +163,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
return run;
}
/**
* Returns the alignment that is applied to the paragraph.
*
* If this attribute is omitted, then null is returned.
* User code can imply the value {@link org.apache.poi.sl.usermodel.TextParagraph.TextAlign#LEFT} then.
*
* @return alignment that is applied to the paragraph
*/
@Override
public TextAlign getTextAlign(){
ParagraphPropertyFetcher<TextAlign> fetcher = new ParagraphPropertyFetcher<TextAlign>(getIndentLevel()){
public boolean fetch(CTTextParagraphProperties props){
@ -186,14 +179,8 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
return fetcher.getValue();
}
/**
* Specifies the alignment that is to be applied to the paragraph.
* Possible values for this include left, right, centered, justified and distributed,
* see {@link org.apache.poi.sl.usermodel.TextParagraph.TextAlign}.
*
* @param align text align
*/
public void setTextAlign(TextAlign align){
@Override
public void setTextAlign(TextAlign align) {
CTTextParagraphProperties pr = _p.isSetPPr() ? _p.getPPr() : _p.addNewPPr();
if(align == null) {
if(pr.isSetAlgn()) pr.unsetAlgn();
@ -816,6 +803,7 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
CTPlaceholder ph = shape.getCTPlaceholder();
if(ph == null){
// if it is a plain text box then take defaults from presentation.xml
@SuppressWarnings("resource")
XMLSlideShow ppt = sheet.getSlideShow();
CTTextParagraphProperties themeProps = ppt.getDefaultParagraphStyle(getIndentLevel());
if (themeProps != null) ok = visitor.fetch(themeProps);

View File

@ -17,8 +17,13 @@
package org.apache.poi.hslf.model.textproperties;
import java.io.*;
import java.util.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.StyleTextPropAtom;
@ -239,6 +244,9 @@ public class TextPropCollection {
* Clones the given text properties
*/
public void copy(TextPropCollection other) {
if (other == null) {
throw new HSLFException("trying to copy null TextPropCollection");
}
if (this == other) return;
this.charactersCovered = other.charactersCovered;
this.indentLevel = other.indentLevel;
@ -264,8 +272,18 @@ public class TextPropCollection {
* Writes out to disk the header, and then all the properties
*/
public void writeOut(OutputStream o) throws IOException {
writeOut(o, false);
}
/**
* Writes out to disk the header, and then all the properties
*/
public void writeOut(OutputStream o, boolean isMasterStyle) throws IOException {
if (!isMasterStyle) {
// First goes the number of characters we affect
// MasterStyles don't have this field
StyleTextPropAtom.writeLittleEndian(charactersCovered,o);
}
// Then we have the indentLevel field if it's a paragraph collection
if (textPropType == TextPropType.paragraph && indentLevel > -1) {

View File

@ -17,14 +17,17 @@
package org.apache.poi.hslf.record;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.LittleEndianOutputStream;
/**
* TxMasterStyleAtom atom (4003).
@ -140,7 +143,7 @@ public final class TxMasterStyleAtom extends RecordAtom {
paragraphStyles = new ArrayList<TextPropCollection>(levels);
charStyles = new ArrayList<TextPropCollection>(levels);
for(short j = 0; j < levels; j++) {
for(short i = 0; i < levels; i++) {
TextPropCollection prprops = new TextPropCollection(0, TextPropType.paragraph); // getParagraphProps(type, j)
if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
// Fetch the 2 byte value, that is safe to ignore for some types of text
@ -163,32 +166,44 @@ public final class TxMasterStyleAtom extends RecordAtom {
pos += chprops.buildTextPropList( head, _data, pos);
charStyles.add(chprops);
}
}
/**
* Paragraph properties for the specified text type and
* indent level
* Depending on the level and type, it may be our special
* ones, or the standard StyleTextPropAtom ones
* Updates the rawdata from the modified paragraph/character styles
*
* @since 3.14-beta1
*/
// protected TextProp[] getParagraphProps(int type, int level){
// return StyleTextPropAtom.paragraphTextPropTypes;
// return (level != 0 || type >= MAX_INDENT)
// ? StyleTextPropAtom.paragraphTextPropTypes
// : paragraphSpecialPropTypes;
// }
public void updateStyles() {
int type = getTextType();
/**
* Character properties for the specified text type and
* indent level.
* Depending on the level and type, it may be our special
* ones, or the standard StyleTextPropAtom ones
*/
// protected TextProp[] getCharacterProps(int type, int level){
// return StyleTextPropAtom.characterTextPropTypes;
// return (level != 0 || type >= MAX_INDENT)
// ? StyleTextPropAtom.characterTextPropTypes
// : characterSpecialPropTypes;
// }
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
LittleEndianOutputStream leos = new LittleEndianOutputStream(bos);
int levels = paragraphStyles.size();
leos.writeShort(levels);
TextPropCollection prdummy = new TextPropCollection(0, TextPropType.paragraph);
TextPropCollection chdummy = new TextPropCollection(0, TextPropType.character);
for (int i=0; i<levels; i++) {
prdummy.copy(paragraphStyles.get(i));
chdummy.copy(charStyles.get(i));
if (type >= TextHeaderAtom.CENTRE_BODY_TYPE) {
leos.writeShort(prdummy.getIndentLevel());
}
// Indent level is not written for master styles
prdummy.setIndentLevel((short)-1);
prdummy.writeOut(bos, true);
chdummy.writeOut(bos, true);
}
_data = bos.toByteArray();
leos.close();
LittleEndian.putInt(_header, 4, _data.length);
} catch (IOException e) {
throw new HSLFException("error in updating master style properties", e);
}
}
}

View File

@ -27,6 +27,7 @@ import org.apache.poi.ddf.EscherContainerRecord;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.CString;
import org.apache.poi.hslf.record.ColorSchemeAtom;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
@ -40,6 +41,7 @@ import org.apache.poi.sl.draw.Drawable;
import org.apache.poi.sl.usermodel.PictureData;
import org.apache.poi.sl.usermodel.ShapeType;
import org.apache.poi.sl.usermodel.Sheet;
import org.apache.poi.util.Internal;
/**
* This class defines the common format of "Sheets" in a powerpoint
@ -119,9 +121,14 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
/**
* Set the SlideShow we're attached to.
* Also passes it on to our child RichTextRuns
* Also passes it on to our child text paragraphs
*/
public void setSlideShow(HSLFSlideShow ss) {
@Internal
protected void setSlideShow(HSLFSlideShow ss) {
if (_slideShow != null) {
throw new HSLFException("Can't change existing slideshow reference");
}
_slideShow = ss;
List<List<HSLFTextParagraph>> trs = getTextParagraphs();
if (trs == null) return;

View File

@ -20,9 +20,11 @@ package org.apache.poi.hslf.usermodel;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.hslf.exceptions.HSLFException;
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.util.Internal;
/**
* SlideMaster determines the graphics, layout, and formatting for all the slides in a given presentation.
@ -73,7 +75,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
/**
* Pickup a style attribute from the master.
* This is the "workhorse" which returns the default style attrubutes.
* This is the "workhorse" which returns the default style attributes.
*/
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
if (_txmaster.length <= txtype) return null;
@ -105,13 +107,14 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
/**
* Assign SlideShow for this slide master.
* (Used interanlly)
*/
public void setSlideShow(HSLFSlideShow ss) {
@Internal
@Override
protected void setSlideShow(HSLFSlideShow ss) {
super.setSlideShow(ss);
//after the slide show is assigned collect all available style records
if (_txmaster == null) {
assert (_txmaster == null);
_txmaster = new TxMasterStyleAtom[9];
TxMasterStyleAtom txdoc = getSlideShow().getDocumentRecord().getEnvironment().getTxMasterStyleAtom();
@ -120,7 +123,31 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
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];
if (txType < _txmaster.length && _txmaster[txType] == null) {
_txmaster[txType] = txrec[i];
}
}
for (List<HSLFTextParagraph> paras : getTextParagraphs()) {
for (HSLFTextParagraph htp : paras) {
int txType = htp.getRunType();
if (txType >= _txmaster.length || _txmaster[txType] == null) {
throw new HSLFException("Master styles not initialized");
}
int level = htp.getIndentLevel();
List<TextPropCollection> charStyles = _txmaster[txType].getCharacterStyles();
List<TextPropCollection> paragraphStyles = _txmaster[txType].getParagraphStyles();
if (charStyles == null || paragraphStyles == null ||
charStyles.size() <= level || paragraphStyles.size() <= level) {
throw new HSLFException("Master styles not initialized");
}
htp.setMasterStyleReference(paragraphStyles.get(level));
for (HSLFTextRun htr : htp.getTextRuns()) {
htr.setMasterStyleReference(charStyles.get(level));
}
}
}
}

View File

@ -68,6 +68,7 @@ import org.apache.poi.hslf.record.RecordTypes;
import org.apache.poi.hslf.record.SlideListWithText;
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
import org.apache.poi.hslf.record.SlidePersistAtom;
import org.apache.poi.hslf.record.TxMasterStyleAtom;
import org.apache.poi.hslf.record.UserEditAtom;
import org.apache.poi.poifs.filesystem.DirectoryNode;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
@ -476,6 +477,23 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
writeDirtyParagraphs(sl);
}
for (HSLFSlideMaster sl : getSlideMasters()) {
boolean isDirty = false;
for (List<HSLFTextParagraph> paras : sl.getTextParagraphs()) {
for (HSLFTextParagraph p : paras) {
isDirty |= p.isDirty();
}
}
if (isDirty) {
for (TxMasterStyleAtom sa : sl.getTxMasterStyleAtoms()) {
if (sa != null) {
// not all master style atoms are set - index 3 is typically null
sa.updateStyles();
}
}
}
}
_hslfSlideShow.write(out);
}

View File

@ -60,6 +60,7 @@ import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.util.Internal;
import org.apache.poi.util.LocaleUtil;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -90,7 +91,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
private final TextHeaderAtom _headerAtom;
private TextBytesAtom _byteAtom;
private TextCharsAtom _charAtom;
private final TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
protected TextRulerAtom _ruler;
protected final List<HSLFTextRun> _runs = new ArrayList<HSLFTextRun>();
@ -151,6 +152,18 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
_paragraphStyle.copy(paragraphStyle);
}
/**
* Setting a master style reference
*
* @param paragraphStyle the master style reference
*
* @since 3.14-Beta1
*/
@Internal
/* package */ void setMasterStyleReference(TextPropCollection paragraphStyle) {
_paragraphStyle = paragraphStyle;
}
/**
* Supply the Sheet we belong to, which might have an assigned SlideShow
* Also passes it on to our child RichTextRuns
@ -344,12 +357,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
return (d != null) ? d : 12d;
}
/**
* 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) {
@Override
public void setTextAlign(TextAlign align) {
Integer alignInt = null;
if (align != null) switch (align) {
default:
@ -365,7 +374,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
}
@Override
public org.apache.poi.sl.usermodel.TextParagraph.TextAlign getTextAlign() {
public TextAlign getTextAlign() {
TextProp tp = getPropVal(_paragraphStyle, "alignment", this);
if (tp == null) return null;
switch (tp.getValue()) {
@ -398,7 +407,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
if (styleTextProp9Atom == null) return null;
TextPFException9[] ant = styleTextProp9Atom.getAutoNumberTypes();
int level = getIndentLevel();
if (ant == null || level >= ant.length) return null;
if (ant == null || level == -1 || level >= ant.length) return null;
return ant[level].getAutoNumberScheme();
}
@ -1224,7 +1233,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
HSLFTextParagraph para = paragraphs.get(paraIdx);
List<HSLFTextRun> runs = para.getTextRuns();
trun = runs.get(runIdx);
int len = trun.getLength();
final int len = trun.getLength();
if (ccRun + len <= ccStyle) {
ccRun += len;
@ -1239,11 +1248,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
ccRun += ccStyle - ccRun;
}
TextPropCollection pCopy = new TextPropCollection(0, TextPropType.character);
pCopy.copy(p);
trun.setCharacterStyle(pCopy);
trun.setCharacterStyle(p);
len = trun.getLength();
if (paraIdx == paragraphs.size()-1 && runIdx == runs.size()-1) {
if (csIdx < charStyles.size() - 1) {
// special case, empty trailing text run
@ -1253,11 +1259,10 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
ccRun++;
} else {
// need to add +1 to the last run of the last paragraph
len++;
trun.getCharacterStyle().updateTextSize(trun.getLength()+1);
ccRun++;
}
}
pCopy.updateTextSize(len);
// need to compare it again, in case a run has been added after
if (++runIdx == runs.size()) {

View File

@ -31,6 +31,7 @@ import org.apache.poi.sl.draw.DrawPaint;
import org.apache.poi.sl.usermodel.PaintStyle;
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
@ -66,10 +67,23 @@ public final class HSLFTextRun implements TextRun {
}
public void setCharacterStyle(TextPropCollection characterStyle) {
assert(characterStyle != null);
this.characterStyle.copy(characterStyle);
this.characterStyle.updateTextSize(_runText.length());
}
/**
* Setting a master style reference
*
* @param characterStyle the master style reference
*
* @since 3.14-Beta1
*/
@Internal
/* package */ void setMasterStyleReference(TextPropCollection characterStyle) {
this.characterStyle = characterStyle;
}
/**
* Supply the SlideShow we belong to
*/

View File

@ -23,6 +23,7 @@ import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
@ -32,7 +33,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.poi.POIDataSamples;
import org.apache.poi.ddf.AbstractEscherOptRecord;
import org.apache.poi.ddf.EscherArrayProperty;
import org.apache.poi.ddf.EscherColorRef;
@ -54,6 +54,7 @@ import org.apache.poi.sl.usermodel.SlideShow;
import org.apache.poi.sl.usermodel.SlideShowFactory;
import org.apache.poi.sl.usermodel.TextBox;
import org.apache.poi.sl.usermodel.TextParagraph;
import org.apache.poi.sl.usermodel.TextParagraph.TextAlign;
import org.apache.poi.sl.usermodel.TextRun;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.StringUtil;
@ -67,8 +68,6 @@ import org.junit.Test;
* @author Yegor Kozlov
*/
public final class TestBugs {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
/**
* Bug 41384: Array index wrong in record creation
*/
@ -680,7 +679,7 @@ public final class TestBugs {
HSLFTextParagraph tp = cell.getTextParagraphs().get(0);
tp.setBulletStyle('%', tp0.getBulletColor(), tp0.getBulletFont(), tp0.getBulletSize());
tp.setIndent(tp0.getIndent());
tp.setAlignment(tp0.getTextAlign());
tp.setTextAlign(tp0.getTextAlign());
tp.setIndentLevel(tp0.getIndentLevel());
tp.setSpaceAfter(tp0.getSpaceAfter());
tp.setSpaceBefore(tp0.getSpaceBefore());
@ -729,7 +728,37 @@ public final class TestBugs {
ppt2.close();
}
@Test
public void bug47904() throws IOException {
HSLFSlideShow ppt1 = new HSLFSlideShow();
HSLFSlideMaster sm = ppt1.getSlideMasters().get(0);
HSLFAutoShape as = (HSLFAutoShape)sm.getShapes().get(0);
HSLFTextParagraph tp = as.getTextParagraphs().get(0);
HSLFTextRun tr = tp.getTextRuns().get(0);
tr.setFontFamily("Tahoma");
tr.setShadowed(true);
tr.setFontSize(44.);
tr.setFontColor(Color.red);
tp.setTextAlign(TextAlign.RIGHT);
ppt1.createSlide().addTitle().setText("foobaa");
HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
ppt1.close();
HSLFTextShape ts = (HSLFTextShape)ppt2.getSlides().get(0).getShapes().get(0);
tp = ts.getTextParagraphs().get(0);
tr = tp.getTextRuns().get(0);
assertEquals(44., tr.getFontSize(), 0);
assertEquals("Tahoma", tr.getFontFamily());
Color colorAct = DrawPaint.applyColorTransform(tr.getFontColor().getSolidColor());
assertEquals(Color.red, colorAct);
assertEquals(TextAlign.RIGHT, tp.getTextAlign());
assertEquals("foobaa", tr.getRawText());
ppt2.close();
}
private static HSLFSlideShow open(String fileName) throws IOException {
return (HSLFSlideShow)SlideShowFactory.create(_slTests.getFile(fileName));
File sample = HSLFTestDataSamples.getSampleFile(fileName);
return (HSLFSlideShow)SlideShowFactory.create(sample);
}
}

View File

@ -19,14 +19,20 @@
package org.apache.poi.hslf.usermodel;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.util.List;
import org.apache.poi.POIDataSamples;
import org.apache.poi.hslf.model.textproperties.TextPFException9;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.*;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
import org.apache.poi.hslf.record.StyleTextProp9Atom;
import org.apache.poi.hslf.record.StyleTextPropAtom;
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
import org.junit.Test;
@ -43,7 +49,7 @@ public final class TestNumberedList3 {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
@Test
public void testNumberedList() throws Exception {
public void testNumberedList() throws IOException {
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("numbers3.ppt"));
assertTrue("No Exceptions while reading file", true);
@ -51,6 +57,7 @@ public final class TestNumberedList3 {
assertEquals(1, slides.size());
final HSLFSlide slide = slides.get(0);
checkSlide(slide);
ppt.close();
}
private void checkSlide(final HSLFSlide s) {
final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();