mirror of https://github.com/apache/poi.git
#62096 - Add support for tabstops
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1823893 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5f71c80131
commit
9968e86b14
|
@ -21,5 +21,12 @@ public interface MasterSheet<
|
|||
S extends Shape<S,P>,
|
||||
P extends TextParagraph<S,P,? extends TextRun>
|
||||
> extends Sheet<S,P> {
|
||||
|
||||
/**
|
||||
* Return the placeholder shape for the specified type
|
||||
*
|
||||
* @return the shape or {@code null} if it is not defined in this mastersheet
|
||||
*
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
SimpleShape<S,P> getPlaceholder(Placeholder type);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/* ====================================================================
|
||||
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.sl.usermodel;
|
||||
|
||||
public interface TabStop {
|
||||
|
||||
enum TabStopType {
|
||||
LEFT(0,1), CENTER(1,2), RIGHT(2,3), DECIMAL(3,4);
|
||||
public final int nativeId;
|
||||
public final int ooxmlId;
|
||||
|
||||
TabStopType(int nativeId, int ooxmlId) {
|
||||
this.nativeId = nativeId;
|
||||
this.ooxmlId = ooxmlId;
|
||||
}
|
||||
public static TabStopType fromNativeId(final int nativeId) {
|
||||
for (TabStopType tst : values()) {
|
||||
if (tst.nativeId == nativeId) {
|
||||
return tst;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static TabStopType fromOoxmlId(final int ooxmlId) {
|
||||
for (TabStopType tst : values()) {
|
||||
if (tst.ooxmlId == ooxmlId) {
|
||||
return tst;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position in points relative to the left side of the paragraph.
|
||||
*
|
||||
* @return position in points
|
||||
*/
|
||||
double getPositionInPoints();
|
||||
|
||||
/**
|
||||
* Sets the position in points relative to the left side of the paragraph
|
||||
*
|
||||
* @param position position in points
|
||||
*/
|
||||
void setPositionInPoints(double position);
|
||||
|
||||
TabStopType getType();
|
||||
|
||||
void setType(TabStopType type);
|
||||
}
|
|
@ -374,4 +374,34 @@ public interface TextParagraph<
|
|||
* @since POI 3.15-beta2
|
||||
*/
|
||||
boolean isHeaderOrFooter();
|
||||
|
||||
|
||||
/**
|
||||
* Get the {@link TabStop TabStops} - the list can't be and it's entries shouldn't be modified.
|
||||
* Opposed to other properties, this method is not cascading to the master sheet,
|
||||
* if the property is not defined on the normal slide level, i.e. the tabstops on
|
||||
* different levels aren't merged.
|
||||
*
|
||||
* @return the tabstop collection or {@code null} if no tabstops are defined
|
||||
*
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
List<? extends TabStop> getTabStops();
|
||||
|
||||
/**
|
||||
* Set the {@link TabStop} collection
|
||||
*
|
||||
* @param tabStops the {@link TabStop} collection
|
||||
*
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
void addTabStops(double positionInPoints, TabStop.TabStopType tabStopType);
|
||||
|
||||
/**
|
||||
* Removes the tabstops of this paragraphs.
|
||||
* This doesn't affect inherited tabstops, e.g. inherited by the slide master
|
||||
*
|
||||
* @since POI 4.0.0
|
||||
*/
|
||||
void clearTabStops();
|
||||
}
|
|
@ -472,6 +472,10 @@ implements XSLFShapeContainer, Sheet<XSLFShape,XSLFTextParagraph> {
|
|||
return null;
|
||||
}
|
||||
|
||||
public XSLFSimpleShape getPlaceholder(Placeholder ph) {
|
||||
return getPlaceholderByType(ph.ooxmlId);
|
||||
}
|
||||
|
||||
XSLFSimpleShape getPlaceholder(CTPlaceholder ph) {
|
||||
XSLFSimpleShape shape = null;
|
||||
if(ph.isSetIdx()) {
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
/* ====================================================================
|
||||
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 org.apache.poi.sl.usermodel.TabStop;
|
||||
import org.apache.poi.util.Units;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextTabAlignType;
|
||||
|
||||
public class XSLFTabStop implements TabStop {
|
||||
|
||||
final CTTextTabStop tabStop;
|
||||
|
||||
XSLFTabStop(CTTextTabStop tabStop) {
|
||||
this.tabStop = tabStop;
|
||||
}
|
||||
|
||||
/** position in EMUs */
|
||||
public int getPosition() {
|
||||
return tabStop.getPos();
|
||||
}
|
||||
|
||||
/** position in EMUs */
|
||||
public void setPosition(final int position) {
|
||||
tabStop.setPos(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPositionInPoints() {
|
||||
return Units.toPoints(getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPositionInPoints(final double points) {
|
||||
setPosition(Units.toEMU(points));
|
||||
}
|
||||
|
||||
public TabStopType getType() {
|
||||
return TabStopType.fromOoxmlId(tabStop.getAlgn().intValue());
|
||||
}
|
||||
|
||||
public void setType(final TabStopType tabStopType) {
|
||||
tabStop.setAlgn(STTextTabAlignType.Enum.forInt(tabStopType.ooxmlId) );
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ import org.apache.poi.sl.draw.DrawPaint;
|
|||
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.TabStop.TabStopType;
|
||||
import org.apache.poi.sl.usermodel.TextParagraph;
|
||||
import org.apache.poi.util.Beta;
|
||||
import org.apache.poi.util.Internal;
|
||||
|
@ -32,26 +33,7 @@ import org.apache.poi.util.Units;
|
|||
import org.apache.poi.xslf.model.ParagraphPropertyFetcher;
|
||||
import org.apache.xmlbeans.XmlCursor;
|
||||
import org.apache.xmlbeans.XmlObject;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTSRgbColor;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextAutonumberBullet;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePercent;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBulletSizePoint;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharBullet;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextField;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextFont;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextLineBreak;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextNormalAutofit;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextSpacing;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStop;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextTabStopList;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAlignType;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextAutonumberScheme;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.STTextFontAlignType;
|
||||
import org.openxmlformats.schemas.drawingml.x2006.main.*;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.CTPlaceholder;
|
||||
import org.openxmlformats.schemas.presentationml.x2006.main.STPlaceholderType;
|
||||
|
||||
|
@ -800,25 +782,27 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
|
|||
|
||||
private <T> boolean fetchParagraphProperty(ParagraphPropertyFetcher<T> visitor){
|
||||
boolean ok = false;
|
||||
XSLFTextShape shape = getParentShape();
|
||||
XSLFSheet sheet = shape.getSheet();
|
||||
final XSLFTextShape shape = getParentShape();
|
||||
final XSLFSheet sheet = shape.getSheet();
|
||||
|
||||
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
|
||||
if (ok) return true;
|
||||
|
||||
ok = shape.fetchShapeProperty(visitor);
|
||||
if (ok) return true;
|
||||
|
||||
|
||||
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);
|
||||
if (!(sheet instanceof XSLFSlideMaster)) {
|
||||
if(_p.isSetPPr()) ok = visitor.fetch(_p.getPPr());
|
||||
if (ok) return true;
|
||||
|
||||
ok = shape.fetchShapeProperty(visitor);
|
||||
if (ok) return true;
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
if (ok) return true;
|
||||
}
|
||||
if (ok) return true;
|
||||
|
||||
// defaults for placeholders are defined in the slide master
|
||||
CTTextParagraphProperties defaultProps = getDefaultMasterStyle();
|
||||
|
@ -1011,7 +995,51 @@ public class XSLFTextParagraph implements TextParagraph<XSLFShape,XSLFTextParagr
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<XSLFTabStop> getTabStops() {
|
||||
ParagraphPropertyFetcher<List<XSLFTabStop>> fetcher = new ParagraphPropertyFetcher<List<XSLFTabStop>>(getIndentLevel()){
|
||||
public boolean fetch(CTTextParagraphProperties props) {
|
||||
if (props.isSetTabLst()) {
|
||||
final List<XSLFTabStop> list = new ArrayList<>();
|
||||
for (final CTTextTabStop ta : props.getTabLst().getTabArray()) {
|
||||
list.add(new XSLFTabStop(ta));
|
||||
}
|
||||
setValue(list);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
fetchParagraphProperty(fetcher);
|
||||
return fetcher.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabStops(double positionInPoints, TabStopType tabStopType) {
|
||||
final XSLFSheet sheet = getParentShape().getSheet();
|
||||
final CTTextParagraphProperties tpp;
|
||||
if (sheet instanceof XSLFSlideMaster) {
|
||||
tpp = getDefaultMasterStyle();
|
||||
} else {
|
||||
final CTTextParagraph xo = getXmlObject();
|
||||
tpp = (xo.isSetPPr()) ? xo.getPPr() : xo.addNewPPr();
|
||||
}
|
||||
final CTTextTabStopList stl = (tpp.isSetTabLst()) ? tpp.getTabLst() : tpp.addNewTabLst();
|
||||
XSLFTabStop tab = new XSLFTabStop(stl.addNewTab());
|
||||
tab.setPositionInPoints(positionInPoints);
|
||||
tab.setType(tabStopType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTabStops() {
|
||||
final XSLFSheet sheet = getParentShape().getSheet();
|
||||
CTTextParagraphProperties tpp = (sheet instanceof XSLFSlideMaster) ? getDefaultMasterStyle() : getXmlObject().getPPr();
|
||||
if (tpp != null && tpp.isSetTabLst()) {
|
||||
tpp.unsetTabLst();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for appending text and keeping paragraph and character properties.
|
||||
* The character properties are moved to the end paragraph marker
|
||||
|
|
|
@ -20,12 +20,16 @@ import static org.junit.Assert.assertEquals;
|
|||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||
import org.apache.poi.sl.usermodel.BaseTestSlideShow;
|
||||
import org.apache.poi.sl.usermodel.SlideShow;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -179,4 +183,25 @@ public class TestXMLSlideShow extends BaseTestSlideShow {
|
|||
xmlComments.close();
|
||||
xml.close();
|
||||
}
|
||||
|
||||
public SlideShow<?, ?> reopen(SlideShow<?, ?> show) {
|
||||
return reopen((XMLSlideShow)show);
|
||||
}
|
||||
|
||||
public static XMLSlideShow reopen(XMLSlideShow show) {
|
||||
try {
|
||||
BufAccessBAOS bos = new BufAccessBAOS();
|
||||
show.write(bos);
|
||||
return new XMLSlideShow(new ByteArrayInputStream(bos.getBuf()));
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BufAccessBAOS extends ByteArrayOutputStream {
|
||||
public byte[] getBuf() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
/* ====================================================================
|
||||
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 org.apache.poi.sl.usermodel.TabStop;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.Units;
|
||||
|
||||
@Internal
|
||||
public class HSLFTabStop implements TabStop, Cloneable {
|
||||
/**
|
||||
* A signed integer that specifies an offset, in master units, of the tab stop.
|
||||
*
|
||||
* 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 HSLFTabStop(int position, TabStopType type) {
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public void setPosition(final int position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getPositionInPoints() {
|
||||
return Units.masterToPoints(getPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPositionInPoints(final double points) {
|
||||
setPosition(Units.pointsToMaster(points));
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabStopType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(TabStopType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HSLFTabStop clone() {
|
||||
try {
|
||||
return (HSLFTabStop)super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + position;
|
||||
result = prime * result + ((type == null) ? 0 : type.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof HSLFTabStop)) {
|
||||
return false;
|
||||
}
|
||||
HSLFTabStop other = (HSLFTabStop) obj;
|
||||
if (position != other.position) {
|
||||
return false;
|
||||
}
|
||||
if (type != other.type) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type + " @ " + position;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/* ====================================================================
|
||||
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.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.sl.usermodel.TabStop.TabStopType;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.LittleEndianByteArrayInputStream;
|
||||
import org.apache.poi.util.LittleEndianConsts;
|
||||
import org.apache.poi.util.LittleEndianInput;
|
||||
import org.apache.poi.util.LittleEndianOutput;
|
||||
import org.apache.poi.util.LittleEndianOutputStream;
|
||||
|
||||
/**
|
||||
* Container for tabstop lists
|
||||
*/
|
||||
@Internal
|
||||
public class HSLFTabStopPropCollection extends TextProp {
|
||||
public static final String NAME = "tabStops";
|
||||
|
||||
private final List<HSLFTabStop> tabStops = new ArrayList<>();
|
||||
|
||||
public HSLFTabStopPropCollection() {
|
||||
super(0, 0x100000, NAME);
|
||||
}
|
||||
|
||||
public HSLFTabStopPropCollection(final HSLFTabStopPropCollection copy) {
|
||||
super(0, copy.getMask(), copy.getName());
|
||||
for (HSLFTabStop ts : copy.tabStops) {
|
||||
tabStops.add(ts.clone());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the tabstops from TxMasterStyle record
|
||||
*
|
||||
* @param data the data stream
|
||||
* @param offset the offset within the data
|
||||
*/
|
||||
public void parseProperty(byte data[], int offset) {
|
||||
tabStops.addAll(readTabStops(new LittleEndianByteArrayInputStream(data, offset)));
|
||||
}
|
||||
|
||||
public static List<HSLFTabStop> readTabStops(final LittleEndianInput lei) {
|
||||
final int count = lei.readUShort();
|
||||
final List<HSLFTabStop> tabs = new ArrayList<>(count);
|
||||
for (int i=0; i<count; i++) {
|
||||
final int position = lei.readShort();
|
||||
final TabStopType type = TabStopType.fromNativeId(lei.readShort());
|
||||
tabs.add(new HSLFTabStop(position, type));
|
||||
}
|
||||
return tabs;
|
||||
}
|
||||
|
||||
|
||||
public void writeProperty(OutputStream out) {
|
||||
writeTabStops(new LittleEndianOutputStream(out), tabStops);
|
||||
}
|
||||
|
||||
public static void writeTabStops(final LittleEndianOutput leo, List<HSLFTabStop> tabStops) {
|
||||
final int count = tabStops.size();
|
||||
leo.writeShort(count);
|
||||
for (HSLFTabStop ts : tabStops) {
|
||||
leo.writeShort(ts.getPosition());
|
||||
leo.writeShort(ts.getType().nativeId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getValue() { return tabStops.size(); }
|
||||
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return LittleEndianConsts.SHORT_SIZE + tabStops.size()*LittleEndianConsts.INT_SIZE;
|
||||
}
|
||||
|
||||
public List<HSLFTabStop> getTabStops() {
|
||||
return tabStops;
|
||||
}
|
||||
|
||||
public void clearTabs() {
|
||||
tabStops.clear();
|
||||
}
|
||||
|
||||
public void addTabStop(HSLFTabStop ts) {
|
||||
tabStops.add(ts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public HSLFTabStopPropCollection clone() {
|
||||
return new HSLFTabStopPropCollection(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = super.hashCode();
|
||||
result = prime * result
|
||||
+ ((tabStops == null) ? 0 : tabStops.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof HSLFTabStopPropCollection)) {
|
||||
return false;
|
||||
}
|
||||
HSLFTabStopPropCollection other = (HSLFTabStopPropCollection) obj;
|
||||
if (!super.equals(other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return tabStops.equals(other.tabStops);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(super.toString());
|
||||
sb.append(" [ ");
|
||||
boolean isFirst = true;
|
||||
for (HSLFTabStop tabStop : tabStops) {
|
||||
if (!isFirst) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(tabStop.getType());
|
||||
sb.append(" @ ");
|
||||
sb.append(tabStop.getPosition());
|
||||
isFirst = false;
|
||||
}
|
||||
sb.append(" ]");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -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.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<TabStop> 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
|
||||
*/
|
||||
public void parseProperty(byte data[], int offset) {
|
||||
int count = LittleEndian.getUShort(data, offset);
|
||||
int off = offset + LittleEndianConsts.SHORT_SIZE;
|
||||
for (int i=0; i<count; i++) {
|
||||
int position = LittleEndian.getShort(data, off);
|
||||
off += LittleEndianConsts.SHORT_SIZE;
|
||||
int recVal = LittleEndian.getShort(data, off);
|
||||
TabStopType type = TabStopType.fromRecordVal(recVal);
|
||||
off += LittleEndianConsts.SHORT_SIZE;
|
||||
tabStops.add(new TabStop(position, type));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return LittleEndianConsts.SHORT_SIZE + tabStops.size()*LittleEndianConsts.INT_SIZE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TabStopPropCollection clone() {
|
||||
TabStopPropCollection other = (TabStopPropCollection)super.clone();
|
||||
other.tabStops = new ArrayList<>();
|
||||
for (TabStop ts : tabStops) {
|
||||
TabStop tso = new TabStop(ts.getPosition(), ts.getType());
|
||||
other.tabStops.add(tso);
|
||||
}
|
||||
return other;
|
||||
}
|
||||
}
|
|
@ -96,7 +96,7 @@ public class TextProp implements Cloneable {
|
|||
try {
|
||||
return (TextProp)super.clone();
|
||||
} catch(CloneNotSupportedException e) {
|
||||
throw new InternalError(e.getMessage());
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,11 +145,11 @@ public class TextProp implements Cloneable {
|
|||
@Override
|
||||
public String toString() {
|
||||
int len;
|
||||
switch (sizeOfDataBlock) {
|
||||
switch (getSize()) {
|
||||
case 1: len = 4; break;
|
||||
case 2: len = 6; break;
|
||||
default: len = 10; break;
|
||||
}
|
||||
return String.format(Locale.ROOT, "%s = %d (%0#"+len+"X mask / %d bytes)", propName, dataValue, maskInHeader, sizeOfDataBlock);
|
||||
return String.format(Locale.ROOT, "%s = %d (%0#"+len+"X mask / %d bytes)", getName(), getValue(), getMask(), getSize());
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ public class TextPropCollection {
|
|||
// 0x200 - Undefined and MUST be ignored
|
||||
new TextProp(2, 0x400, "bullet.offset"), // indent
|
||||
new TextProp(2, 0x8000, "defaultTabSize"),
|
||||
new TabStopPropCollection(), // tabstops size is variable!
|
||||
new HSLFTabStopPropCollection(), // tabstops size is variable!
|
||||
new FontAlignmentProp(),
|
||||
new WrapFlagsTextProp(),
|
||||
new TextProp(2, 0x200000, "textDirection"),
|
||||
|
@ -130,12 +130,14 @@ public class TextPropCollection {
|
|||
}
|
||||
|
||||
/** Fetch the TextProp with this name, or null if it isn't present */
|
||||
public final TextProp findByName(String textPropName) {
|
||||
return textProps.get(textPropName);
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends TextProp> T findByName(String textPropName) {
|
||||
return (T)textProps.get(textPropName);
|
||||
}
|
||||
|
||||
public final TextProp removeByName(String name) {
|
||||
return textProps.remove(name);
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends TextProp> T removeByName(String name) {
|
||||
return (T)textProps.remove(name);
|
||||
}
|
||||
|
||||
public final TextPropType getTextPropType() {
|
||||
|
@ -153,10 +155,11 @@ public class TextPropCollection {
|
|||
* @param name the property name
|
||||
* @return if found, the property template to copy from
|
||||
*/
|
||||
private TextProp validatePropName(String name) {
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T extends TextProp> T validatePropName(final String name) {
|
||||
for (TextProp tp : getPotentialProperties()) {
|
||||
if (tp.getName().equals(name)) {
|
||||
return tp;
|
||||
return (T)tp;
|
||||
}
|
||||
}
|
||||
String errStr =
|
||||
|
@ -166,13 +169,14 @@ public class TextPropCollection {
|
|||
}
|
||||
|
||||
/** Add the TextProp with this name to the list */
|
||||
public final TextProp addWithName(String name) {
|
||||
@SuppressWarnings("unchecked")
|
||||
public final <T extends TextProp> T addWithName(final String name) {
|
||||
// Find the base TextProp to base on
|
||||
TextProp existing = findByName(name);
|
||||
T existing = findByName(name);
|
||||
if (existing != null) return existing;
|
||||
|
||||
// Add a copy of this property
|
||||
TextProp textProp = validatePropName(name).clone();
|
||||
T textProp = (T)validatePropName(name).clone();
|
||||
textProps.put(name,textProp);
|
||||
return textProp;
|
||||
}
|
||||
|
@ -218,11 +222,13 @@ public class TextPropCollection {
|
|||
// Bingo, data contains this property
|
||||
TextProp prop = tp.clone();
|
||||
int val = 0;
|
||||
if (prop.getSize() == 2) {
|
||||
if (prop instanceof HSLFTabStopPropCollection) {
|
||||
((HSLFTabStopPropCollection)prop).parseProperty(data, dataOffset+bytesPassed);
|
||||
} else if (prop.getSize() == 2) {
|
||||
val = LittleEndian.getShort(data,dataOffset+bytesPassed);
|
||||
} else if(prop.getSize() == 4) {
|
||||
val = LittleEndian.getInt(data,dataOffset+bytesPassed);
|
||||
} else if (prop.getSize() == 0 && !(prop instanceof TabStopPropCollection)) {
|
||||
} else if (prop.getSize() == 0) {
|
||||
//remember "special" bits.
|
||||
maskSpecial |= tp.getMask();
|
||||
continue;
|
||||
|
@ -230,9 +236,7 @@ public class TextPropCollection {
|
|||
|
||||
if (prop instanceof BitMaskTextProp) {
|
||||
((BitMaskTextProp)prop).setValueWithMask(val, containsField);
|
||||
} else if (prop instanceof TabStopPropCollection) {
|
||||
((TabStopPropCollection)prop).parseProperty(data, dataOffset+bytesPassed);
|
||||
} else {
|
||||
} else if (!(prop instanceof HSLFTabStopPropCollection)) {
|
||||
prop.setValue(val);
|
||||
}
|
||||
bytesPassed += prop.getSize();
|
||||
|
@ -311,6 +315,8 @@ public class TextPropCollection {
|
|||
StyleTextPropAtom.writeLittleEndian((short)val,o);
|
||||
} else if (textProp.getSize() == 4) {
|
||||
StyleTextPropAtom.writeLittleEndian(val,o);
|
||||
} else if (textProp instanceof HSLFTabStopPropCollection) {
|
||||
((HSLFTabStopPropCollection)textProp).writeProperty(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -359,8 +365,9 @@ public class TextPropCollection {
|
|||
out.append(" indent level: "+getIndentLevel()+"\n");
|
||||
}
|
||||
for(TextProp p : getTextPropList()) {
|
||||
out.append(" " + p.getName() + " = " + p.getValue() );
|
||||
out.append(" (0x" + HexDump.toHex(p.getValue()) + ")\n");
|
||||
out.append(" ");
|
||||
out.append(p.toString());
|
||||
out.append("\n");
|
||||
if (p instanceof BitMaskTextProp) {
|
||||
BitMaskTextProp bm = (BitMaskTextProp)p;
|
||||
int i = 0;
|
||||
|
|
|
@ -17,11 +17,21 @@
|
|||
|
||||
package org.apache.poi.hslf.record;
|
||||
|
||||
import static org.apache.poi.util.BitFieldFactory.getInstance;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.util.IOUtils;
|
||||
import org.apache.poi.hslf.model.textproperties.HSLFTabStop;
|
||||
import org.apache.poi.hslf.model.textproperties.HSLFTabStopPropCollection;
|
||||
import org.apache.poi.util.BitField;
|
||||
import org.apache.poi.util.LittleEndian;
|
||||
import org.apache.poi.util.LittleEndianByteArrayInputStream;
|
||||
import org.apache.poi.util.LittleEndianOutputStream;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
/**
|
||||
|
@ -31,33 +41,38 @@ public final class TextRulerAtom extends RecordAtom {
|
|||
|
||||
//arbitrarily selected; may need to increase
|
||||
private static final int MAX_RECORD_LENGTH = 100_000;
|
||||
|
||||
private static final BitField DEFAULT_TAB_SIZE = getInstance(0x0001);
|
||||
private static final BitField C_LEVELS = getInstance(0x0002);
|
||||
private static final BitField TAB_STOPS = getInstance(0x0004);
|
||||
private static final BitField[] LEFT_MARGIN = {
|
||||
getInstance(0x0008), getInstance(0x0010), getInstance(0x0020),
|
||||
getInstance(0x0040), getInstance(0x0080),
|
||||
};
|
||||
private static final BitField[] INDENT = {
|
||||
getInstance(0x0100), getInstance(0x0200), getInstance(0x0400),
|
||||
getInstance(0x0800), getInstance(0x1000),
|
||||
};
|
||||
|
||||
/**
|
||||
* Record header.
|
||||
*/
|
||||
private byte[] _header;
|
||||
|
||||
/**
|
||||
* Record data.
|
||||
*/
|
||||
private byte[] _data;
|
||||
private final byte[] _header = new byte[8];
|
||||
|
||||
//ruler internals
|
||||
private int defaultTabSize;
|
||||
private int numLevels;
|
||||
private int[] tabStops;
|
||||
private int[] bulletOffsets = new int[5];
|
||||
private int[] textOffsets = new int[5];
|
||||
private Integer defaultTabSize;
|
||||
private Integer numLevels;
|
||||
private final List<HSLFTabStop> tabStops = new ArrayList<>();
|
||||
//bullet.offset
|
||||
private final Integer[] leftMargin = new Integer[5];
|
||||
//text.offset
|
||||
private final Integer[] indent = new Integer[5];
|
||||
|
||||
/**
|
||||
* Constructs a new empty ruler atom.
|
||||
*/
|
||||
public TextRulerAtom() {
|
||||
_header = new byte[8];
|
||||
_data = new byte[0];
|
||||
|
||||
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||
LittleEndian.putInt(_header, 4, _data.length);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,18 +83,17 @@ public final class TextRulerAtom extends RecordAtom {
|
|||
* @param start the start offset into the byte array.
|
||||
* @param len the length of the slice in the byte array.
|
||||
*/
|
||||
protected TextRulerAtom(byte[] source, int start, int len) {
|
||||
// Get the header.
|
||||
_header = new byte[8];
|
||||
System.arraycopy(source,start,_header,0,8);
|
||||
|
||||
// Get the record data.
|
||||
_data = IOUtils.safelyAllocate(len-8, MAX_RECORD_LENGTH);
|
||||
System.arraycopy(source,start+8,_data,0,len-8);
|
||||
protected TextRulerAtom(final byte[] source, final int start, final int len) {
|
||||
final LittleEndianByteArrayInputStream leis = new LittleEndianByteArrayInputStream(source, start, Math.min(len, MAX_RECORD_LENGTH));
|
||||
|
||||
|
||||
try {
|
||||
read();
|
||||
} catch (Exception e){
|
||||
// Get the header.
|
||||
leis.read(_header);
|
||||
|
||||
// Get the record data.
|
||||
read(leis);
|
||||
} catch (IOException e){
|
||||
logger.log(POILogger.ERROR, "Failed to parse TextRulerAtom: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -89,6 +103,7 @@ public final class TextRulerAtom extends RecordAtom {
|
|||
*
|
||||
* @return the record type.
|
||||
*/
|
||||
@Override
|
||||
public long getRecordType() {
|
||||
return RecordTypes.TextRulerAtom.typeID;
|
||||
}
|
||||
|
@ -100,109 +115,110 @@ public final class TextRulerAtom extends RecordAtom {
|
|||
* @param out the output stream to write to.
|
||||
* @throws java.io.IOException if an error occurs.
|
||||
*/
|
||||
public void writeOut(OutputStream out) throws IOException {
|
||||
@Override
|
||||
public void writeOut(final OutputStream out) throws IOException {
|
||||
final ByteArrayOutputStream bos = new ByteArrayOutputStream(200);
|
||||
final LittleEndianOutputStream lbos = new LittleEndianOutputStream(bos);
|
||||
int mask = 0;
|
||||
mask |= writeIf(lbos, numLevels, C_LEVELS);
|
||||
mask |= writeIf(lbos, defaultTabSize, DEFAULT_TAB_SIZE);
|
||||
mask |= writeIf(lbos, tabStops, TAB_STOPS);
|
||||
for (int i=0; i<5; i++) {
|
||||
mask |= writeIf(lbos, leftMargin[i], LEFT_MARGIN[i]);
|
||||
mask |= writeIf(lbos, indent[i], INDENT[i]);
|
||||
}
|
||||
LittleEndian.putInt(_header, 4, bos.size()+4);
|
||||
out.write(_header);
|
||||
out.write(_data);
|
||||
LittleEndian.putUShort(mask, out);
|
||||
LittleEndian.putUShort(0, out);
|
||||
bos.writeTo(out);
|
||||
}
|
||||
|
||||
private static int writeIf(final LittleEndianOutputStream lbos, Integer value, BitField bit) {
|
||||
boolean isSet = false;
|
||||
if (value != null) {
|
||||
lbos.writeShort(value);
|
||||
isSet = true;
|
||||
}
|
||||
return bit.setBoolean(0, isSet);
|
||||
}
|
||||
|
||||
private static int writeIf(final LittleEndianOutputStream lbos, List<HSLFTabStop> value, BitField bit) {
|
||||
boolean isSet = false;
|
||||
if (value != null && !value.isEmpty()) {
|
||||
HSLFTabStopPropCollection.writeTabStops(lbos, value);
|
||||
isSet = true;
|
||||
}
|
||||
return bit.setBoolean(0, isSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the record bytes and initialize the internal variables
|
||||
*/
|
||||
private void read(){
|
||||
int pos = 0;
|
||||
short mask = LittleEndian.getShort(_data); pos += 4;
|
||||
short val;
|
||||
int[] bits = {1, 0, 2, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12};
|
||||
for (int i = 0; i < bits.length; i++) {
|
||||
if((mask & 1 << bits[i]) != 0){
|
||||
switch (bits[i]){
|
||||
case 0:
|
||||
//defaultTabSize
|
||||
defaultTabSize = LittleEndian.getShort(_data, pos); pos += 2;
|
||||
break;
|
||||
case 1:
|
||||
//numLevels
|
||||
numLevels = LittleEndian.getShort(_data, pos); pos += 2;
|
||||
break;
|
||||
case 2:
|
||||
//tabStops
|
||||
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||
tabStops = new int[val*2];
|
||||
for (int j = 0; j < tabStops.length; j++) {
|
||||
tabStops[j] = LittleEndian.getUShort(_data, pos); pos += 2;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
//bullet.offset
|
||||
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||
bulletOffsets[bits[i]-3] = val;
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
//text.offset
|
||||
val = LittleEndian.getShort(_data, pos); pos += 2;
|
||||
textOffsets[bits[i]-8] = val;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private void read(final LittleEndianByteArrayInputStream leis) {
|
||||
final int mask = leis.readInt();
|
||||
numLevels = readIf(leis, mask, C_LEVELS);
|
||||
defaultTabSize = readIf(leis, mask, DEFAULT_TAB_SIZE);
|
||||
if (TAB_STOPS.isSet(mask)) {
|
||||
tabStops.addAll(HSLFTabStopPropCollection.readTabStops(leis));
|
||||
}
|
||||
for (int i=0; i<5; i++) {
|
||||
leftMargin[i] = readIf(leis, mask, LEFT_MARGIN[i]);
|
||||
indent[i] = readIf(leis, mask, INDENT[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static Integer readIf(final LittleEndianByteArrayInputStream leis, final int mask, final BitField bit) {
|
||||
return (bit.isSet(mask)) ? (int)leis.readShort() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default distance between tab stops, in master coordinates (576 dpi).
|
||||
*/
|
||||
public int getDefaultTabSize(){
|
||||
return defaultTabSize;
|
||||
return defaultTabSize == null ? 0 : defaultTabSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of indent levels (maximum 5).
|
||||
*/
|
||||
public int getNumberOfLevels(){
|
||||
return numLevels;
|
||||
return numLevels == null ? 0 : numLevels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default distance between tab stops, in master coordinates (576 dpi).
|
||||
*/
|
||||
public int[] getTabStops(){
|
||||
public List<HSLFTabStop> getTabStops(){
|
||||
return tabStops;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paragraph's distance from shape's left margin, in master coordinates (576 dpi).
|
||||
*/
|
||||
public int[] getTextOffsets(){
|
||||
return textOffsets;
|
||||
public Integer[] getTextOffsets(){
|
||||
return indent;
|
||||
}
|
||||
|
||||
/**
|
||||
* First line of paragraph's distance from shape's left margin, in master coordinates (576 dpi).
|
||||
*/
|
||||
public int[] getBulletOffsets(){
|
||||
return bulletOffsets;
|
||||
public Integer[] getBulletOffsets(){
|
||||
return leftMargin;
|
||||
}
|
||||
|
||||
public static TextRulerAtom getParagraphInstance(){
|
||||
byte[] data = new byte[] {
|
||||
0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,
|
||||
0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01
|
||||
};
|
||||
return new TextRulerAtom(data, 0, data.length);
|
||||
final TextRulerAtom tra = new TextRulerAtom();
|
||||
tra.indent[0] = 249;
|
||||
tra.indent[1] = tra.leftMargin[1] = 321;
|
||||
return tra;
|
||||
}
|
||||
|
||||
public void setParagraphIndent(short tetxOffset, short bulletOffset){
|
||||
LittleEndian.putShort(_data, 4, tetxOffset);
|
||||
LittleEndian.putShort(_data, 6, bulletOffset);
|
||||
LittleEndian.putShort(_data, 8, bulletOffset);
|
||||
public void setParagraphIndent(short leftMargin, short indent) {
|
||||
Arrays.fill(this.leftMargin, null);
|
||||
Arrays.fill(this.indent, null);
|
||||
this.leftMargin[0] = (int)leftMargin;
|
||||
this.indent[0] = (int)indent;
|
||||
this.indent[1] = (int)indent;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,16 +17,13 @@
|
|||
|
||||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.record.SheetContainer;
|
||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
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<HSLFShape,HSLFTextParagraph> {
|
||||
public HSLFMasterSheet(SheetContainer container, int sheetNo){
|
||||
|
@ -34,10 +31,19 @@ public abstract class HSLFMasterSheet extends HSLFSheet implements MasterSheet<H
|
|||
}
|
||||
|
||||
/**
|
||||
* Pickup a style attribute from the master.
|
||||
* This is the "workhorse" which returns the default style attrubutes.
|
||||
* Find the master collection for the given txtype/level/name.
|
||||
* This is the "workhorse" which returns the default style attributes.
|
||||
* If {@code name = "*"} return the current collection, otherwise if the name is not found
|
||||
* in the current selection of txtype/level/name, first try lower levels then try parent types,
|
||||
* if it wasn't found there return {@code null}.
|
||||
*
|
||||
* @param txtype the {@link TextHeaderAtom} type
|
||||
* @param level the indent level of the paragraph, if the level is not defined for the found
|
||||
* collection, the highest existing level will be used
|
||||
* @param name the property name,
|
||||
* @param isCharacter if {@code true} use character styles, otherwise use paragraph styles
|
||||
*/
|
||||
public abstract TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) ;
|
||||
public abstract TextPropCollection getPropCollection(int txtype, int level, String name, boolean isCharacter);
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -74,42 +74,50 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
|
|||
}
|
||||
|
||||
/**
|
||||
* Pickup a style attribute from the master.
|
||||
* Find the master collection for the given txtype/level/name.
|
||||
* This is the "workhorse" which returns the default style attributes.
|
||||
* If {@code name = "*"} return the current collection, otherwise if the name is not found
|
||||
* in the current selection of txtype/level/name, first try lower levels then try parent types,
|
||||
* if it wasn't found there return {@code null}.
|
||||
*
|
||||
* @param txtype the {@link TextHeaderAtom} type
|
||||
* @param level the indent level of the paragraph, if the level is not defined for the found
|
||||
* collection, the highest existing level will be used
|
||||
* @param name the property name,
|
||||
* @param isCharacter if {@code true} use character styles, otherwise use paragraph styles
|
||||
*/
|
||||
@Override
|
||||
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
|
||||
if (_txmaster.length <= txtype) {
|
||||
return null;
|
||||
}
|
||||
TxMasterStyleAtom t = _txmaster[txtype];
|
||||
List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles();
|
||||
|
||||
TextProp prop = null;
|
||||
for (int i = Math.min(level, styles.size()-1); prop == null && i >= 0; i--) {
|
||||
prop = styles.get(i).findByName(name);
|
||||
public TextPropCollection getPropCollection(final int txtype, final int level, final String name, final boolean isCharacter) {
|
||||
if (txtype < _txmaster.length) {
|
||||
final TxMasterStyleAtom t = _txmaster[txtype];
|
||||
final List<TextPropCollection> styles = isCharacter ? t.getCharacterStyles() : t.getParagraphStyles();
|
||||
// TODO: what is the reaction for readOnly=false and styles.isEmpty()?
|
||||
final int minLevel = Math.min(level, styles.size()-1);
|
||||
if ("*".equals(name)) {
|
||||
return styles.get(minLevel);
|
||||
}
|
||||
|
||||
for (int i=minLevel; i >= 0; i--) {
|
||||
final TextPropCollection col = styles.get(i);
|
||||
final TextProp tp = col.findByName(name);
|
||||
if (tp != null) {
|
||||
return col;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (prop != null) {
|
||||
return prop;
|
||||
}
|
||||
|
||||
switch (txtype) {
|
||||
case TextHeaderAtom.CENTRE_BODY_TYPE:
|
||||
case TextHeaderAtom.HALF_BODY_TYPE:
|
||||
case TextHeaderAtom.QUARTER_BODY_TYPE:
|
||||
txtype = TextHeaderAtom.BODY_TYPE;
|
||||
break;
|
||||
return getPropCollection(TextHeaderAtom.BODY_TYPE, level, name, isCharacter);
|
||||
case TextHeaderAtom.CENTER_TITLE_TYPE:
|
||||
txtype = TextHeaderAtom.TITLE_TYPE;
|
||||
break;
|
||||
return getPropCollection(TextHeaderAtom.TITLE_TYPE, level, name, isCharacter);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return getStyleAttribute(txtype, level, name, isCharacter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Assign SlideShow for this slide master.
|
||||
*/
|
||||
|
@ -132,7 +140,7 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
|
|||
_txmaster[txType] = txrec[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (List<HSLFTextParagraph> paras : getTextParagraphs()) {
|
||||
for (HSLFTextParagraph htp : paras) {
|
||||
int txType = htp.getRunType();
|
||||
|
@ -148,11 +156,6 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
|
|||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,12 +24,16 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.poi.common.usermodel.fonts.FontGroup;
|
||||
import org.apache.poi.common.usermodel.fonts.FontInfo;
|
||||
import org.apache.poi.hslf.exceptions.HSLFException;
|
||||
import org.apache.poi.hslf.model.textproperties.BitMaskTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.FontAlignmentProp;
|
||||
import org.apache.poi.hslf.model.textproperties.HSLFTabStop;
|
||||
import org.apache.poi.hslf.model.textproperties.HSLFTabStopPropCollection;
|
||||
import org.apache.poi.hslf.model.textproperties.IndentProp;
|
||||
import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextAlignmentProp;
|
||||
|
@ -37,34 +41,15 @@ import org.apache.poi.hslf.model.textproperties.TextPFException9;
|
|||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
|
||||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||||
import org.apache.poi.hslf.record.EscherTextboxWrapper;
|
||||
import org.apache.poi.hslf.record.InteractiveInfo;
|
||||
import org.apache.poi.hslf.record.MasterTextPropAtom;
|
||||
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.RecordContainer;
|
||||
import org.apache.poi.hslf.record.RecordTypes;
|
||||
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
|
||||
import org.apache.poi.hslf.record.SlideListWithText;
|
||||
import org.apache.poi.hslf.record.SlidePersistAtom;
|
||||
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.record.TxInteractiveInfoAtom;
|
||||
import org.apache.poi.hslf.record.*;
|
||||
import org.apache.poi.sl.draw.DrawPaint;
|
||||
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
|
||||
import org.apache.poi.sl.usermodel.MasterSheet;
|
||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
|
||||
import org.apache.poi.sl.usermodel.Placeholder;
|
||||
import org.apache.poi.sl.usermodel.TabStop;
|
||||
import org.apache.poi.sl.usermodel.TabStop.TabStopType;
|
||||
import org.apache.poi.sl.usermodel.TextParagraph;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
import org.apache.poi.util.StringUtil;
|
||||
|
@ -93,7 +78,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
private TextBytesAtom _byteAtom;
|
||||
private TextCharsAtom _charAtom;
|
||||
private TextPropCollection _paragraphStyle = new TextPropCollection(1, TextPropType.paragraph);
|
||||
private TextPropCollection _masterStyle;
|
||||
|
||||
protected TextRulerAtom _ruler;
|
||||
protected final List<HSLFTextRun> _runs = new ArrayList<>();
|
||||
|
@ -107,6 +91,33 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
|
||||
private final List<HSLFTextParagraph> parentList;
|
||||
|
||||
private class HSLFTabStopDecorator implements TabStop {
|
||||
final HSLFTabStop tabStop;
|
||||
|
||||
HSLFTabStopDecorator(final HSLFTabStop tabStop) {
|
||||
this.tabStop = tabStop;
|
||||
}
|
||||
|
||||
public double getPositionInPoints() {
|
||||
return tabStop.getPositionInPoints();
|
||||
}
|
||||
|
||||
public void setPositionInPoints(double position) {
|
||||
tabStop.setPositionInPoints(position);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
public TabStopType getType() {
|
||||
return tabStop.getType();
|
||||
}
|
||||
|
||||
public void setType(TabStopType type) {
|
||||
tabStop.setType(type);
|
||||
setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a Text Run from a Unicode text block.
|
||||
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
|
||||
|
@ -160,18 +171,6 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
_paragraphStyle.copy(paragraphStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting a master style reference
|
||||
*
|
||||
* @param paragraphStyle the master style reference
|
||||
*
|
||||
* @since POI 3.14-Beta1
|
||||
*/
|
||||
@Internal
|
||||
/* package */ void setMasterStyleReference(TextPropCollection masterStyle) {
|
||||
_masterStyle = masterStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
||||
* Also passes it on to our child RichTextRuns
|
||||
|
@ -341,7 +340,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
|
||||
@Override
|
||||
public Double getLeftMargin() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "text.offset");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "text.offset");
|
||||
return (tp == null) ? null : Units.masterToPoints(tp.getValue());
|
||||
}
|
||||
|
||||
|
@ -364,7 +363,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
|
||||
@Override
|
||||
public Double getIndent() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.offset");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "bullet.offset");
|
||||
return (tp == null) ? null : Units.masterToPoints(tp.getValue());
|
||||
}
|
||||
|
||||
|
@ -388,7 +387,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
if (fontInfo == null) {
|
||||
fontInfo = HSLFFontInfoPredefined.ARIAL;
|
||||
}
|
||||
|
||||
|
||||
return fontInfo.getTypeface();
|
||||
}
|
||||
|
||||
|
@ -422,7 +421,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
|
||||
@Override
|
||||
public TextAlign getTextAlign() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "alignment");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "alignment");
|
||||
if (tp == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -440,7 +439,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
|
||||
@Override
|
||||
public FontAlign getFontAlign() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, FontAlignmentProp.NAME);
|
||||
TextProp tp = getPropVal(_paragraphStyle, FontAlignmentProp.NAME);
|
||||
if (tp == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -606,7 +605,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* Returns the bullet character
|
||||
*/
|
||||
public Character getBulletChar() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.char");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "bullet.char");
|
||||
return (tp == null) ? null : (char)tp.getValue();
|
||||
}
|
||||
|
||||
|
@ -637,7 +636,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* Returns the bullet color
|
||||
*/
|
||||
public Color getBulletColor() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.color");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "bullet.color");
|
||||
boolean hasColor = getFlag(ParagraphFlagsTextProp.BULLET_HARDCOLOR_IDX);
|
||||
if (tp == null || !hasColor) {
|
||||
// if bullet color is undefined, return color of first run
|
||||
|
@ -661,7 +660,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
*/
|
||||
public void setBulletFont(String typeface) {
|
||||
if (typeface == null) {
|
||||
setPropVal(_paragraphStyle, _masterStyle, "bullet.font", null);
|
||||
setPropVal(_paragraphStyle, "bullet.font", null);
|
||||
setFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX, false);
|
||||
return;
|
||||
}
|
||||
|
@ -677,7 +676,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* Returns the bullet font
|
||||
*/
|
||||
public String getBulletFont() {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, "bullet.font");
|
||||
TextProp tp = getPropVal(_paragraphStyle, "bullet.font");
|
||||
boolean hasFont = getFlag(ParagraphFlagsTextProp.BULLET_HARDFONT_IDX);
|
||||
if (tp == null || !hasFont) {
|
||||
return getDefaultFontFamily();
|
||||
|
@ -723,8 +722,64 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<? extends TabStop> getTabStops() {
|
||||
final List<HSLFTabStop> tabStops;
|
||||
final TextRulerAtom textRuler;
|
||||
if (getSheet() instanceof HSLFSlideMaster) {
|
||||
final HSLFTabStopPropCollection tpc = getMasterPropVal(_paragraphStyle, HSLFTabStopPropCollection.NAME);
|
||||
if (tpc == null) {
|
||||
return null;
|
||||
}
|
||||
tabStops = tpc.getTabStops();
|
||||
textRuler = null;
|
||||
} else {
|
||||
textRuler = (TextRulerAtom)_headerAtom.getParentRecord().findFirstOfType(RecordTypes.TextRulerAtom.typeID);
|
||||
if (textRuler == null) {
|
||||
return null;
|
||||
}
|
||||
tabStops = textRuler.getTabStops();
|
||||
}
|
||||
|
||||
return tabStops.stream().map((tabStop) -> new HSLFTabStopDecorator(tabStop)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTabStops(final double positionInPoints, final TabStopType tabStopType) {
|
||||
final HSLFTabStop ts = new HSLFTabStop(0, tabStopType);
|
||||
ts.setPositionInPoints(positionInPoints);
|
||||
|
||||
if (getSheet() instanceof HSLFSlideMaster) {
|
||||
final Consumer<HSLFTabStopPropCollection> con = (tp) -> tp.addTabStop(ts);
|
||||
setPropValInner(_paragraphStyle, HSLFTabStopPropCollection.NAME, con);
|
||||
} else {
|
||||
final RecordContainer cont = _headerAtom.getParentRecord();
|
||||
TextRulerAtom textRuler = (TextRulerAtom)cont.findFirstOfType(RecordTypes.TextRulerAtom.typeID);
|
||||
if (textRuler == null) {
|
||||
textRuler = TextRulerAtom.getParagraphInstance();
|
||||
cont.appendChildRecord(textRuler);
|
||||
}
|
||||
textRuler.getTabStops().add(ts);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTabStops() {
|
||||
if (getSheet() instanceof HSLFSlideMaster) {
|
||||
setPropValInner(_paragraphStyle, HSLFTabStopPropCollection.NAME, null);
|
||||
} else {
|
||||
final RecordContainer cont = _headerAtom.getParentRecord();
|
||||
final TextRulerAtom textRuler = (TextRulerAtom)cont.findFirstOfType(RecordTypes.TextRulerAtom.typeID);
|
||||
if (textRuler == null) {
|
||||
return;
|
||||
}
|
||||
textRuler.getTabStops().clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Double getPctOrPoints(String propName) {
|
||||
TextProp tp = getPropVal(_paragraphStyle, _masterStyle, propName);
|
||||
TextProp tp = getPropVal(_paragraphStyle, propName);
|
||||
if (tp == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -741,7 +796,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
}
|
||||
|
||||
private boolean getFlag(int index) {
|
||||
BitMaskTextProp tp = (BitMaskTextProp)getPropVal(_paragraphStyle, _masterStyle, ParagraphFlagsTextProp.NAME);
|
||||
BitMaskTextProp tp = getPropVal(_paragraphStyle, ParagraphFlagsTextProp.NAME);
|
||||
return (tp == null) ? false : tp.getSubValue(index);
|
||||
}
|
||||
|
||||
|
@ -759,56 +814,54 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* The propName can be a comma-separated list, in case multiple equivalent values
|
||||
* are queried
|
||||
*/
|
||||
protected TextProp getPropVal(TextPropCollection props, TextPropCollection masterProps, String propName) {
|
||||
protected <T extends TextProp> T getPropVal(TextPropCollection props, String propName) {
|
||||
String propNames[] = propName.split(",");
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = props.findByName(pn);
|
||||
T prop = props.findByName(pn);
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
|
||||
return getMasterPropVal(props, masterProps, propName);
|
||||
return getMasterPropVal(props, propName);
|
||||
}
|
||||
|
||||
private TextProp getMasterPropVal(TextPropCollection props, TextPropCollection masterProps, String propName) {
|
||||
private <T extends TextProp> T getMasterPropVal(final TextPropCollection props, final String propName) {
|
||||
boolean isChar = props.getTextPropType() == TextPropType.character;
|
||||
|
||||
// check if we can delegate to master for the property
|
||||
if (!isChar) {
|
||||
BitMaskTextProp maskProp = (BitMaskTextProp) props.findByName(ParagraphFlagsTextProp.NAME);
|
||||
BitMaskTextProp maskProp = props.findByName(ParagraphFlagsTextProp.NAME);
|
||||
boolean hardAttribute = (maskProp != null && maskProp.getValue() == 0);
|
||||
if (hardAttribute) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String propNames[] = propName.split(",");
|
||||
if (masterProps == null) {
|
||||
HSLFSheet sheet = getSheet();
|
||||
int txtype = getRunType();
|
||||
HSLFMasterSheet master = sheet.getMasterSheet();
|
||||
final String propNames[] = propName.split(",");
|
||||
final HSLFSheet sheet = getSheet();
|
||||
final int txtype = getRunType();
|
||||
final HSLFMasterSheet master;
|
||||
if (sheet instanceof HSLFMasterSheet) {
|
||||
master = (HSLFMasterSheet)sheet;
|
||||
} else {
|
||||
master = sheet.getMasterSheet();
|
||||
if (master == null) {
|
||||
logger.log(POILogger.WARN, "MasterSheet is not available");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = master.getStyleAttribute(txtype, getIndentLevel(), pn, isChar);
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (String pn : propNames) {
|
||||
TextProp prop = masterProps.findByName(pn);
|
||||
for (String pn : propNames) {
|
||||
TextPropCollection masterProps = master.getPropCollection(txtype, getIndentLevel(), pn, isChar);
|
||||
if (masterProps != null) {
|
||||
T prop = masterProps.findByName(pn);
|
||||
if (isValidProp(prop)) {
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -826,22 +879,33 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* @param name the name of the TextProp to fetch/add
|
||||
* @param val the value, null if unset
|
||||
*/
|
||||
protected void setPropVal(TextPropCollection props, TextPropCollection masterProps, String name, Integer val) {
|
||||
TextPropCollection pc = props;
|
||||
if (getSheet() instanceof MasterSheet && masterProps != null) {
|
||||
pc = masterProps;
|
||||
}
|
||||
|
||||
if (val == null) {
|
||||
pc.removeByName(name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch / Add the TextProp
|
||||
TextProp tp = pc.addWithName(name);
|
||||
tp.setValue(val);
|
||||
protected void setPropVal(final TextPropCollection props, final String name, final Integer val) {
|
||||
setPropValInner(props, name, val == null ? null : tp -> tp.setValue(val));
|
||||
}
|
||||
|
||||
private void setPropValInner(final TextPropCollection props, final String name, Consumer<? extends TextProp> handler) {
|
||||
final boolean isChar = props.getTextPropType() == TextPropType.character;
|
||||
|
||||
final TextPropCollection pc;
|
||||
if (_sheet instanceof HSLFMasterSheet) {
|
||||
pc = ((HSLFMasterSheet)_sheet).getPropCollection(getRunType(), getIndentLevel(), "*", isChar);
|
||||
if (pc == null) {
|
||||
throw new HSLFException("Master text property collection can't be determined.");
|
||||
}
|
||||
} else {
|
||||
pc = props;
|
||||
}
|
||||
|
||||
if (handler == null) {
|
||||
pc.removeByName(name);
|
||||
} else {
|
||||
// Fetch / Add the TextProp
|
||||
handler.accept(pc.addWithName(name));
|
||||
}
|
||||
setDirty();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check and add linebreaks to text runs leading other paragraphs
|
||||
*
|
||||
|
@ -1595,7 +1659,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||
* @param val The value to set for the TextProp
|
||||
*/
|
||||
public void setParagraphTextPropVal(String propName, Integer val) {
|
||||
setPropVal(_paragraphStyle, _masterStyle, propName, val);
|
||||
setPropVal(_paragraphStyle, propName, val);
|
||||
setDirty();
|
||||
}
|
||||
|
||||
|
|
|
@ -36,7 +36,6 @@ import org.apache.poi.sl.usermodel.Placeholder;
|
|||
import org.apache.poi.sl.usermodel.TextParagraph;
|
||||
import org.apache.poi.sl.usermodel.TextRun;
|
||||
import org.apache.poi.sl.usermodel.TextShape;
|
||||
import org.apache.poi.util.Internal;
|
||||
import org.apache.poi.util.POILogFactory;
|
||||
import org.apache.poi.util.POILogger;
|
||||
|
||||
|
@ -61,8 +60,6 @@ public final class HSLFTextRun implements TextRun {
|
|||
*/
|
||||
private TextPropCollection characterStyle = new TextPropCollection(1, TextPropType.character);
|
||||
|
||||
private TextPropCollection masterStyle;
|
||||
|
||||
/**
|
||||
* Create a new wrapper around a rich text string
|
||||
* @param parentParagraph the parent paragraph
|
||||
|
@ -80,19 +77,6 @@ public final class HSLFTextRun implements TextRun {
|
|||
this.characterStyle.updateTextSize(_runText.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Setting a master style reference
|
||||
*
|
||||
* @param characterStyle the master style reference
|
||||
*
|
||||
* @since POI 3.14-Beta1
|
||||
*/
|
||||
@Internal
|
||||
/* package */ void setMasterStyleReference(TextPropCollection masterStyle) {
|
||||
this.masterStyle = masterStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Supply the SlideShow we belong to
|
||||
*/
|
||||
|
@ -149,28 +133,34 @@ public final class HSLFTextRun implements TextRun {
|
|||
}
|
||||
|
||||
protected boolean getFlag(int index) {
|
||||
if (characterStyle == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
BitMaskTextProp prop = (BitMaskTextProp)characterStyle.findByName(CharFlagsTextProp.NAME);
|
||||
BitMaskTextProp prop = (characterStyle == null) ? null : characterStyle.findByName(CharFlagsTextProp.NAME);
|
||||
|
||||
if (prop == null || !prop.getSubPropMatches()[index]) {
|
||||
int txtype = parentParagraph.getRunType();
|
||||
HSLFSheet sheet = parentParagraph.getSheet();
|
||||
if (sheet != null) {
|
||||
HSLFMasterSheet master = sheet.getMasterSheet();
|
||||
if (master != null){
|
||||
prop = (BitMaskTextProp)master.getStyleAttribute(txtype, parentParagraph.getIndentLevel(), CharFlagsTextProp.NAME, true);
|
||||
}
|
||||
} else {
|
||||
logger.log(POILogger.WARN, "MasterSheet is not available");
|
||||
}
|
||||
prop = getMasterProp(CharFlagsTextProp.NAME);
|
||||
}
|
||||
|
||||
return prop == null ? false : prop.getSubValue(index);
|
||||
}
|
||||
|
||||
private <T extends TextProp> T getMasterProp(final String name) {
|
||||
final int txtype = parentParagraph.getRunType();
|
||||
final HSLFSheet sheet = parentParagraph.getSheet();
|
||||
if (sheet == null) {
|
||||
logger.log(POILogger.ERROR, "Sheet is not available");
|
||||
return null;
|
||||
}
|
||||
|
||||
final HSLFMasterSheet master = sheet.getMasterSheet();
|
||||
if (master == null) {
|
||||
logger.log(POILogger.WARN, "MasterSheet is not available");
|
||||
return null;
|
||||
}
|
||||
|
||||
final TextPropCollection col = master.getPropCollection(txtype, parentParagraph.getIndentLevel(), name, true);
|
||||
return (col == null) ? null : col.findByName(name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value of the given flag in the CharFlagsTextProp, adding
|
||||
* it if required.
|
||||
|
@ -189,8 +179,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
* @param val The value to set for the TextProp
|
||||
*/
|
||||
public void setCharTextPropVal(String propName, Integer val) {
|
||||
getTextParagraph().setPropVal(characterStyle, masterStyle, propName, val);
|
||||
getTextParagraph().setDirty();
|
||||
getTextParagraph().setPropVal(characterStyle, propName, val);
|
||||
}
|
||||
|
||||
|
||||
|
@ -270,7 +259,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
* @return the percentage of the font size. If the value is positive, it is superscript, otherwise it is subscript
|
||||
*/
|
||||
public int getSuperscript() {
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "superscript");
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, "superscript");
|
||||
return tp == null ? 0 : tp.getValue();
|
||||
}
|
||||
|
||||
|
@ -285,7 +274,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
|
||||
@Override
|
||||
public Double getFontSize() {
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.size");
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, "font.size");
|
||||
return tp == null ? null : (double)tp.getValue();
|
||||
}
|
||||
|
||||
|
@ -300,7 +289,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
* Gets the font index
|
||||
*/
|
||||
public int getFontIndex() {
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.index");
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, "font.index");
|
||||
return tp == null ? -1 : tp.getValue();
|
||||
}
|
||||
|
||||
|
@ -401,7 +390,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
break;
|
||||
}
|
||||
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, propName);
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, propName);
|
||||
return (tp != null) ? slideShow.getFont(tp.getValue()) : null;
|
||||
}
|
||||
|
||||
|
@ -410,7 +399,7 @@ public final class HSLFTextRun implements TextRun {
|
|||
*/
|
||||
@Override
|
||||
public SolidPaint getFontColor() {
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, masterStyle, "font.color");
|
||||
TextProp tp = getTextParagraph().getPropVal(characterStyle, "font.color");
|
||||
if (tp == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ 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.SlideAtom;
|
||||
|
||||
/**
|
||||
|
@ -55,11 +55,11 @@ public final class HSLFTitleMaster extends HSLFMasterSheet {
|
|||
* Delegate the call to the underlying slide master.
|
||||
*/
|
||||
@Override
|
||||
public TextProp getStyleAttribute(int txtype, int level, String name, boolean isCharacter) {
|
||||
HSLFMasterSheet master = getMasterSheet();
|
||||
return (master == null) ? null : master.getStyleAttribute(txtype, level, name, isCharacter);
|
||||
public TextPropCollection getPropCollection(final int txtype, final int level, final String name, final boolean isCharacter) {
|
||||
final HSLFMasterSheet master = getMasterSheet();
|
||||
return (master == null) ? null : master.getPropCollection(txtype, level, name, isCharacter);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the slide master for this title master.
|
||||
*/
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
|
||||
package org.apache.poi.hslf.model;
|
||||
|
||||
import static org.apache.poi.hslf.record.TextHeaderAtom.BODY_TYPE;
|
||||
import static org.apache.poi.hslf.record.TextHeaderAtom.CENTER_TITLE_TYPE;
|
||||
import static org.apache.poi.hslf.record.TextHeaderAtom.CENTRE_BODY_TYPE;
|
||||
import static org.apache.poi.hslf.record.TextHeaderAtom.TITLE_TYPE;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
|
@ -27,6 +31,7 @@ import java.util.List;
|
|||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||
import org.apache.poi.hslf.record.Environment;
|
||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||
import org.apache.poi.hslf.usermodel.HSLFMasterSheet;
|
||||
|
@ -51,62 +56,70 @@ public final class TestSlideMaster {
|
|||
*/
|
||||
@Test
|
||||
public void testSlideMaster() throws IOException {
|
||||
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt"));
|
||||
final HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt"));
|
||||
|
||||
Environment env = ppt.getDocumentRecord().getEnvironment();
|
||||
final Environment env = ppt.getDocumentRecord().getEnvironment();
|
||||
|
||||
List<HSLFSlideMaster> master = ppt.getSlideMasters();
|
||||
assertEquals(2, master.size());
|
||||
assertEquals(2, ppt.getSlideMasters().size());
|
||||
|
||||
//character attributes
|
||||
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());
|
||||
assertEquals(40, getMasterVal(ppt, 0, TITLE_TYPE, "font.size", true));
|
||||
assertEquals(48, getMasterVal(ppt, 1, TITLE_TYPE, "font.size", true));
|
||||
|
||||
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();
|
||||
int font1 = getMasterVal(ppt, 0, TITLE_TYPE, "font.index", true);
|
||||
int font2 = getMasterVal(ppt, 1, TITLE_TYPE, "font.index", true);
|
||||
assertEquals("Arial", env.getFontCollection().getFontInfo(font1).getTypeface());
|
||||
assertEquals("Georgia", env.getFontCollection().getFontInfo(font2).getTypeface());
|
||||
|
||||
CharFlagsTextProp prop1 = (CharFlagsTextProp)master.get(0).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true);
|
||||
CharFlagsTextProp prop1 = getMasterProp(ppt, 0, TITLE_TYPE, "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.get(1).getStyleAttribute(TextHeaderAtom.TITLE_TYPE, 0, "char_flags", true);
|
||||
CharFlagsTextProp prop2 = getMasterProp(ppt, 1, TITLE_TYPE, "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.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());
|
||||
assertEquals(0x266B, getMasterVal(ppt, 0, BODY_TYPE, "bullet.char", false));
|
||||
assertEquals(0x2022, getMasterVal(ppt, 1, BODY_TYPE, "bullet.char", false));
|
||||
|
||||
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();
|
||||
int b1 = getMasterVal(ppt, 0, BODY_TYPE, "bullet.font", false);
|
||||
int b2 = getMasterVal(ppt, 1, BODY_TYPE, "bullet.font", false);
|
||||
assertEquals("Arial", env.getFontCollection().getFontInfo(b1).getTypeface());
|
||||
assertEquals("Georgia", env.getFontCollection().getFontInfo(b2).getTypeface());
|
||||
|
||||
ppt.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T extends TextProp> T getMasterProp(HSLFSlideShow ppt, int masterIdx, int txtype, String propName, boolean isCharacter) {
|
||||
return (T)ppt.getSlideMasters().get(masterIdx).getPropCollection(txtype, 0, propName, isCharacter).findByName(propName);
|
||||
}
|
||||
|
||||
private static int getMasterVal(HSLFSlideShow ppt, int masterIdx, int txtype, String propName, boolean isCharacter) {
|
||||
return getMasterProp(ppt, masterIdx, txtype, propName, isCharacter).getValue();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test we can read default text attributes for a title master sheet
|
||||
*/
|
||||
@Test
|
||||
public void testTitleMasterTextAttributes() throws IOException {
|
||||
HSLFSlideShow ppt = new HSLFSlideShow(_slTests.openResourceAsStream("slide_master.ppt"));
|
||||
List<HSLFTitleMaster> master = ppt.getTitleMasters();
|
||||
assertEquals(1, master.size());
|
||||
assertEquals(1, ppt.getTitleMasters().size());
|
||||
|
||||
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(40, getMasterVal(ppt, 0, CENTER_TITLE_TYPE, "font.size", true));
|
||||
CharFlagsTextProp prop1 = getMasterProp(ppt, 0, CENTER_TITLE_TYPE, "char_flags", true);
|
||||
assertEquals(false, prop1.getSubValue(CharFlagsTextProp.BOLD_IDX));
|
||||
assertEquals(false, prop1.getSubValue(CharFlagsTextProp.ITALIC_IDX));
|
||||
assertEquals(true, prop1.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
|
||||
|
||||
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(32, getMasterVal(ppt, 0, CENTRE_BODY_TYPE, "font.size", true));
|
||||
CharFlagsTextProp prop2 = getMasterProp(ppt, 0, CENTRE_BODY_TYPE, "char_flags", true);
|
||||
assertEquals(false, prop2.getSubValue(CharFlagsTextProp.BOLD_IDX));
|
||||
assertEquals(false, prop2.getSubValue(CharFlagsTextProp.ITALIC_IDX));
|
||||
assertEquals(false, prop2.getSubValue(CharFlagsTextProp.UNDERLINE_IDX));
|
||||
|
||||
|
|
|
@ -18,17 +18,17 @@
|
|||
package org.apache.poi.hslf.record;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.List;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import org.apache.poi.hslf.model.textproperties.HSLFTabStop;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests TextRulerAtom
|
||||
*
|
||||
* @author Yegor Kozlov
|
||||
*/
|
||||
public final class TestTextRulerAtom extends TestCase {
|
||||
public final class TestTextRulerAtom {
|
||||
|
||||
//from a real file
|
||||
private final byte[] data_1 = new byte[] {
|
||||
|
@ -40,25 +40,27 @@ public final class TestTextRulerAtom extends TestCase {
|
|||
|
||||
private final byte[] data_2 = new byte[] {
|
||||
0x00, 0x00, (byte)0xA6, 0x0F, 0x0A, 0x00, 0x00, 0x00,
|
||||
0x10, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01
|
||||
0x08, 0x03, 0x00, 0x00, (byte)0xF9, 0x00, 0x41, 0x01, 0x41, 0x01
|
||||
};
|
||||
|
||||
@Test
|
||||
public void testReadRuler() {
|
||||
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);
|
||||
assertEquals(ruler.getNumberOfLevels(), 0);
|
||||
assertEquals(ruler.getDefaultTabSize(), 0);
|
||||
|
||||
int[] tabStops = ruler.getTabStops();
|
||||
assertNull(tabStops);
|
||||
List<HSLFTabStop> tabStops = ruler.getTabStops();
|
||||
assertNotNull(tabStops);
|
||||
|
||||
int[] textOffsets = ruler.getTextOffsets();
|
||||
assertArrayEquals(new int[]{226, 451, 903, 1129, 1526}, textOffsets);
|
||||
Integer[] textOffsets = ruler.getTextOffsets();
|
||||
assertArrayEquals(new Integer[]{226, 451, 903, 1129, 1526}, textOffsets);
|
||||
|
||||
int[] bulletOffsets = ruler.getBulletOffsets();
|
||||
assertArrayEquals(new int[]{117, 345, 794, 1016, 1526}, bulletOffsets);
|
||||
Integer[] bulletOffsets = ruler.getBulletOffsets();
|
||||
assertArrayEquals(new Integer[]{117, 345, 794, 1016, 1526}, bulletOffsets);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWriteRuler() throws Exception {
|
||||
TextRulerAtom ruler = new TextRulerAtom(data_1, 0, data_1.length);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
@ -68,6 +70,7 @@ public final class TestTextRulerAtom extends TestCase {
|
|||
assertArrayEquals(result, data_1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRead2() throws Exception {
|
||||
TextRulerAtom ruler = TextRulerAtom.getParagraphInstance();
|
||||
ruler.setParagraphIndent((short)249, (short)321);
|
||||
|
@ -75,6 +78,6 @@ public final class TestTextRulerAtom extends TestCase {
|
|||
ruler.writeOut(out);
|
||||
|
||||
byte[] result = out.toByteArray();
|
||||
assertArrayEquals(result, data_2);
|
||||
assertArrayEquals(data_2, result);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,8 +17,14 @@
|
|||
package org.apache.poi.hslf.usermodel;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.poi.sl.usermodel.BaseTestSlideShow;
|
||||
import org.apache.poi.sl.usermodel.SlideShow;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestHSLFSlideShow extends BaseTestSlideShow {
|
||||
|
@ -32,4 +38,25 @@ public class TestHSLFSlideShow extends BaseTestSlideShow {
|
|||
public void dummy() {
|
||||
assertNotNull(createSlideShow());
|
||||
}
|
||||
|
||||
public SlideShow<?, ?> reopen(SlideShow<?, ?> show) {
|
||||
return reopen((HSLFSlideShow)show);
|
||||
}
|
||||
|
||||
public static HSLFSlideShow reopen(HSLFSlideShow show) {
|
||||
try {
|
||||
BufAccessBAOS bos = new BufAccessBAOS();
|
||||
show.write(bos);
|
||||
return new HSLFSlideShow(new ByteArrayInputStream(bos.getBuf()));
|
||||
} catch (IOException e) {
|
||||
fail(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class BufAccessBAOS extends ByteArrayOutputStream {
|
||||
public byte[] getBuf() {
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,18 +21,24 @@ import static org.junit.Assert.assertNotNull;
|
|||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.poi.POIDataSamples;
|
||||
import org.apache.poi.sl.usermodel.PictureData.PictureType;
|
||||
import org.apache.poi.sl.usermodel.TabStop.TabStopType;
|
||||
import org.junit.Test;
|
||||
|
||||
public abstract class BaseTestSlideShow {
|
||||
protected static final POIDataSamples slTests = POIDataSamples.getSlideShowInstance();
|
||||
|
||||
public abstract SlideShow<?, ?> createSlideShow();
|
||||
|
||||
public abstract SlideShow<?, ?> reopen(SlideShow<?, ?> show);
|
||||
|
||||
@Test
|
||||
public void addPicture_File() throws IOException {
|
||||
|
@ -92,4 +98,63 @@ public abstract class BaseTestSlideShow {
|
|||
|
||||
show.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addTabStops() throws IOException {
|
||||
try (final SlideShow<?,?> show1 = createSlideShow()) {
|
||||
// first set the TabStops in the Master sheet
|
||||
final MasterSheet<?, ?> master1 = show1.getSlideMasters().get(0);
|
||||
final AutoShape<?, ?> master1_as = (AutoShape<?,?>)master1.getPlaceholder(Placeholder.BODY);
|
||||
final TextParagraph<?, ?, ? extends TextRun> master1_tp = master1_as.getTextParagraphs().get(0);
|
||||
master1_tp.clearTabStops();
|
||||
int i1 = 0;
|
||||
for (final TabStopType tst : TabStopType.values()) {
|
||||
master1_tp.addTabStops(10+i1*10, tst);
|
||||
i1++;
|
||||
}
|
||||
|
||||
// then set it on a normal slide
|
||||
final Slide<?,?> slide1 = show1.createSlide();
|
||||
final AutoShape<?, ?> slide1_as = slide1.createAutoShape();
|
||||
slide1_as.setText("abc");
|
||||
slide1_as.setAnchor(new Rectangle2D.Double(100,100,100,100));
|
||||
final TextParagraph<?, ?, ? extends TextRun> slide1_tp = slide1_as.getTextParagraphs().get(0);
|
||||
slide1_tp.getTextRuns().get(0).setFontColor(new Color(0x563412));
|
||||
slide1_tp.clearTabStops();
|
||||
int i2 = 0;
|
||||
for (final TabStopType tst : TabStopType.values()) {
|
||||
slide1_tp.addTabStops(15+i2*5, tst);
|
||||
i2++;
|
||||
}
|
||||
|
||||
try (final SlideShow<?, ?> show2 = reopen(show1)) {
|
||||
final MasterSheet<?, ?> master2 = show2.getSlideMasters().get(0);
|
||||
final AutoShape<?, ?> master2_as = (AutoShape<?,?>)master2.getPlaceholder(Placeholder.BODY);
|
||||
final TextParagraph<?, ?, ? extends TextRun> master2_tp = master2_as.getTextParagraphs().get(0);
|
||||
final List<? extends TabStop> master2_tabStops = master2_tp.getTabStops();
|
||||
assertNotNull(master2_tabStops);
|
||||
int i3 = 0;
|
||||
for (final TabStopType tst : TabStopType.values()) {
|
||||
final TabStop ts = master2_tabStops.get(i3);
|
||||
assertEquals(10+i3*10, ts.getPositionInPoints(), 0.0);
|
||||
assertEquals(tst, ts.getType());
|
||||
i3++;
|
||||
}
|
||||
|
||||
|
||||
final Slide<?,?> slide2 = show2.getSlides().get(0);
|
||||
final AutoShape<?,?> slide2_as = (AutoShape<?,?>)slide2.getShapes().get(0);
|
||||
final TextParagraph<?, ?, ? extends TextRun> slide2_tp = slide2_as.getTextParagraphs().get(0);
|
||||
final List<? extends TabStop> slide2_tabStops = slide2_tp.getTabStops();
|
||||
assertNotNull(slide2_tabStops);
|
||||
int i4 = 0;
|
||||
for (final TabStopType tst : TabStopType.values()) {
|
||||
final TabStop ts = slide2_tabStops.get(i4);
|
||||
assertEquals(15+i4*5, ts.getPositionInPoints(), 0.0);
|
||||
assertEquals(tst, ts.getType());
|
||||
i4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue