diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java index 5d345e6de..1fc4ec993 100755 --- a/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/AutoShapes.java @@ -369,5 +369,12 @@ public class AutoShapes { } }; + shapes[ShapeTypes.StraightConnector1] = new ShapeOutline(){ + public java.awt.Shape getOutline(Shape shape){ + return new Line2D.Float(0, 0, 21600, 21600); + } + }; + + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java b/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java index d31237f8d..fb3980a45 100755 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Freeform.java @@ -19,6 +19,7 @@ package org.apache.poi.hslf.model; import org.apache.poi.ddf.*; import org.apache.poi.util.LittleEndian; import org.apache.poi.util.POILogger; +import org.apache.poi.util.HexDump; import java.awt.geom.*; import java.util.ArrayList; @@ -185,10 +186,6 @@ public class Freeform extends AutoShape { return null; } - Rectangle2D bounds = getAnchor2D(); - float right = (float)bounds.getX(); - float bottom = (float)bounds.getY(); - GeneralPath path = new GeneralPath(); int numPoints = verticesProp.getNumberOfElementsInArray(); int numSegments = segmentsProp.getNumberOfElementsInArray(); @@ -199,8 +196,8 @@ public class Freeform extends AutoShape { short x = LittleEndian.getShort(p, 0); short y = LittleEndian.getShort(p, 2); path.moveTo( - ((float)x*POINT_DPI/MASTER_DPI + right), - ((float)y*POINT_DPI/MASTER_DPI + bottom)); + ((float)x*POINT_DPI/MASTER_DPI), + ((float)y*POINT_DPI/MASTER_DPI)); } else if (Arrays.equals(elem, SEGMENTINFO_CUBICTO) || Arrays.equals(elem, SEGMENTINFO_CUBICTO2)){ i++; byte[] p1 = verticesProp.getElement(j++); @@ -213,9 +210,9 @@ public class Freeform extends AutoShape { short x3 = LittleEndian.getShort(p3, 0); short y3 = LittleEndian.getShort(p3, 2); path.curveTo( - ((float)x1*POINT_DPI/MASTER_DPI + right), ((float)y1*POINT_DPI/MASTER_DPI + bottom), - ((float)x2*POINT_DPI/MASTER_DPI + right), ((float)y2*POINT_DPI/MASTER_DPI + bottom), - ((float)x3*POINT_DPI/MASTER_DPI + right), ((float)y3*POINT_DPI/MASTER_DPI + bottom)); + ((float)x1*POINT_DPI/MASTER_DPI), ((float)y1*POINT_DPI/MASTER_DPI), + ((float)x2*POINT_DPI/MASTER_DPI), ((float)y2*POINT_DPI/MASTER_DPI), + ((float)x3*POINT_DPI/MASTER_DPI), ((float)y3*POINT_DPI/MASTER_DPI)); } else if (Arrays.equals(elem, SEGMENTINFO_LINETO)){ i++; @@ -226,18 +223,26 @@ public class Freeform extends AutoShape { short x = LittleEndian.getShort(p, 0); short y = LittleEndian.getShort(p, 2); path.lineTo( - ((float)x*POINT_DPI/MASTER_DPI + right), ((float)y*POINT_DPI/MASTER_DPI + bottom)); + ((float)x*POINT_DPI/MASTER_DPI), ((float)y*POINT_DPI/MASTER_DPI)); } } else if (Arrays.equals(pnext, SEGMENTINFO_CLOSE)){ path.closePath(); } } } - return path; } public java.awt.Shape getOutline(){ - return getPath(); + GeneralPath path = getPath(); + Rectangle2D anchor = getAnchor2D(); + Rectangle2D bounds = path.getBounds2D(); + AffineTransform at = new AffineTransform(); + at.translate(anchor.getX(), anchor.getY()); + at.scale( + anchor.getWidth()/bounds.getWidth(), + anchor.getHeight()/bounds.getHeight() + ); + return at.createTransformedShape(path); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java index 5b1b1016e..d01136d87 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/MasterSheet.java @@ -67,4 +67,21 @@ public abstract class MasterSheet extends Sheet { } return false; } + + /** + * Return placeholder by text type + */ + public TextShape getPlaceholder(int type){ + Shape[] shape = getShapes(); + for (int i = 0; i < shape.length; i++) { + if(shape[i] instanceof TextShape){ + TextShape tx = (TextShape)shape[i]; + TextRun run = tx.getTextRun(); + if(run != null && run.getRunType() == type){ + return tx; + } + } + } + return null; + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java index e10986966..375249b51 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Picture.java @@ -28,6 +28,7 @@ import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.awt.*; import java.awt.geom.Rectangle2D; +import java.awt.geom.AffineTransform; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -244,6 +245,9 @@ public class Picture extends SimpleShape { } public void draw(Graphics2D graphics){ + AffineTransform at = graphics.getTransform(); + ShapePainter.paint(this, graphics); + PictureData data = getPictureData(); if (data instanceof Bitmap){ BufferedImage img = null; @@ -260,5 +264,6 @@ public class Picture extends SimpleShape { } else { logger.log(POILogger.WARN, "Rendering of metafiles is not yet supported. image.type: " + (data == null ? "NA" : data.getClass().getName())); } + graphics.setTransform(at); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java index e96e34900..fbea17e88 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Shape.java @@ -341,58 +341,7 @@ public abstract class Shape { * @param sh - owning shape */ protected void afterInsert(Sheet sh){ - PPDrawing ppdrawing = sh.getPPDrawing(); - EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0]; - - EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID); - - int id = allocateShapeId(dg); - setShapeId(id); - } - - /** - * Allocates new shape id for the new drawing group id. - * - * @param dg EscherDgRecord of the sheet that owns the shape being created - * - * @return a new shape id. - */ - protected int allocateShapeId(EscherDgRecord dg) - { - EscherDggRecord dgg = _sheet.getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); - if(dgg == null){ - logger.log(POILogger.ERROR, "EscherDggRecord not found"); - return 0; - } - - dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 ); - - // Add to existing cluster if space available - for (int i = 0; i < dgg.getFileIdClusters().length; i++) - { - EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i]; - if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024) - { - int result = c.getNumShapeIdsUsed() + (1024 * (i+1)); - c.incrementShapeId(); - dg.setNumShapes( dg.getNumShapes() + 1 ); - dg.setLastMSOSPID( result ); - if (result >= dgg.getShapeIdMax()) - dgg.setShapeIdMax( result + 1 ); - return result; - } - } - - // Create new cluster - dgg.addCluster( dg.getDrawingGroupId(), 0 ); - dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId(); - dg.setNumShapes( dg.getNumShapes() + 1 ); - int result = (1024 * dgg.getFileIdClusters().length); - dg.setLastMSOSPID( result ); - if (result >= dgg.getShapeIdMax()) - dgg.setShapeIdMax( result + 1 ); - return result; } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java index b57a6e233..cfa829671 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/ShapeGroup.java @@ -196,13 +196,8 @@ public class ShapeGroup extends Shape{ Sheet sheet = getSheet(); shape.setSheet(sheet); + shape.setShapeId(sheet.allocateShapeId()); shape.afterInsert(sheet); - - if (shape instanceof TextShape) { - TextShape tbox = (TextShape) shape; - EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper(); - if(txWrapper != null) getSheet().getPPDrawing().addTextboxWrapper(txWrapper); - } } /** @@ -277,20 +272,9 @@ public class ShapeGroup extends Shape{ } public void draw(Graphics2D graphics){ - Rectangle2D anchor = getAnchor2D(); - Rectangle2D coords = getCoordinates(); - //transform coordinates AffineTransform at = graphics.getTransform(); - /* - if(!anchor.equals(coords)){ - graphics.scale(anchor.getWidth()/coords.getWidth(), anchor.getHeight()/coords.getHeight()); - graphics.translate( - anchor.getX()*coords.getWidth()/anchor.getWidth() - coords.getX(), - anchor.getY()*coords.getHeight()/anchor.getHeight() - coords.getY()); - } - */ Shape[] sh = getShapes(); for (int i = 0; i < sh.length; i++) { sh[i].draw(graphics); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java index d9c8903d5..6eb84ca2e 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java @@ -18,12 +18,10 @@ package org.apache.poi.hslf.model; -import org.apache.poi.ddf.EscherContainerRecord; -import org.apache.poi.ddf.EscherDgRecord; -import org.apache.poi.ddf.EscherRecord; -import org.apache.poi.ddf.EscherSpRecord; +import org.apache.poi.ddf.*; import org.apache.poi.hslf.record.*; import org.apache.poi.hslf.usermodel.SlideShow; +import org.apache.poi.util.POILogger; import java.util.ArrayList; import java.util.Iterator; @@ -248,15 +246,47 @@ public abstract class Sheet { spgr.addChildRecord(shape.getSpContainer()); shape.setSheet(this); + shape.setShapeId(allocateShapeId()); shape.afterInsert(this); + } - // If it's a TextShape, we need to tell the PPDrawing, as it has to - // track TextboxWrappers specially - if (shape instanceof TextShape) { - TextShape tbox = (TextShape) shape; - EscherTextboxWrapper txWrapper = tbox.getEscherTextboxWrapper(); - if(txWrapper != null) ppdrawing.addTextboxWrapper(txWrapper); + /** + * Allocates new shape id for the new drawing group id. + * + * @return a new shape id. + */ + public int allocateShapeId() + { + EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord(); + EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord(); + + dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 ); + + // Add to existing cluster if space available + for (int i = 0; i < dgg.getFileIdClusters().length; i++) + { + EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i]; + if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024) + { + int result = c.getNumShapeIdsUsed() + (1024 * (i+1)); + c.incrementShapeId(); + dg.setNumShapes( dg.getNumShapes() + 1 ); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; + } } + + // Create new cluster + dgg.addCluster( dg.getDrawingGroupId(), 0, false ); + dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId(); + dg.setNumShapes( dg.getNumShapes() + 1 ); + int result = (1024 * dgg.getFileIdClusters().length); + dg.setLastMSOSPID( result ); + if (result >= dgg.getShapeIdMax()) + dgg.setShapeIdMax( result + 1 ); + return result; } /** @@ -284,6 +314,13 @@ public abstract class Sheet { return lst.remove(shape.getSpContainer()); } + /** + * Called by SlideShow ater a new sheet is created + */ + public void onCreate(){ + + } + /** * Return the master sheet . */ diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java index ea0719a7f..e15454d65 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java @@ -126,8 +126,8 @@ public class SimpleShape extends Shape { EscherSimpleProperty p2 = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.LINESTYLE__NOLINEDRAWDASH); int p2val = p2 == null ? 0 : p2.getPropertyValue(); Color clr = null; - if (p1 != null && (p2val & 0x8) != 0){ - int rgb = p1.getPropertyValue(); + if ((p2val & 0x8) != 0 || (p2val & 0x10) != 0){ + int rgb = p1 == null ? 0 : p1.getPropertyValue(); if (rgb >= 0x8000000) { int idx = rgb % 0x8000000; if(getSheet() != null) { diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java index e618ae230..bb99c1bca 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Slide.java @@ -21,12 +21,17 @@ package org.apache.poi.hslf.model; import java.util.Vector; +import java.util.Iterator; import java.awt.*; import org.apache.poi.hslf.record.SlideAtom; import org.apache.poi.hslf.record.TextHeaderAtom; import org.apache.poi.hslf.record.ColorSchemeAtom; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; +import org.apache.poi.ddf.EscherDggRecord; +import org.apache.poi.ddf.EscherContainerRecord; +import org.apache.poi.ddf.EscherDgRecord; +import org.apache.poi.ddf.EscherSpRecord; /** * This class represents a slide in a PowerPoint Document. It allows @@ -126,6 +131,42 @@ public class Slide extends Sheet _slideNo = newSlideNumber; } + /** + * Called by SlideShow ater a new slide is created. + *
+ * For Slide we need to do the following: + *
TextBox
object that represents the slide's title.
*
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java b/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java
index 26870dbdb..b48edfc1a 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/SlideMaster.java
@@ -92,6 +92,7 @@ public class SlideMaster extends MasterSheet {
} else {
switch (txtype) {
case TextHeaderAtom.CENTRE_BODY_TYPE:
+ case TextHeaderAtom.HALF_BODY_TYPE:
case TextHeaderAtom.QUARTER_BODY_TYPE:
txtype = TextHeaderAtom.BODY_TYPE;
break;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
index c1eadc336..6eff54329 100755
--- a/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextPainter.java
@@ -17,6 +17,7 @@
package org.apache.poi.hslf.model;
import org.apache.poi.hslf.usermodel.RichTextRun;
+import org.apache.poi.hslf.record.TextRulerAtom;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.POILogFactory;
@@ -38,6 +39,13 @@ import java.util.ArrayList;
public class TextPainter {
protected POILogger logger = POILogFactory.getLogger(this.getClass());
+ /**
+ * Display unicode square if a bullet char can't be displayed,
+ * for example, if Wingdings font is used.
+ * TODO: map Wingdngs and Symbol to unicode Arial
+ */
+ protected static final char DEFAULT_BULLET_CHAR = '\u25a0';
+
protected TextShape _shape;
public TextPainter(TextShape shape){
@@ -49,6 +57,10 @@ public class TextPainter {
*/
public AttributedString getAttributedString(TextRun txrun){
String text = txrun.getText();
+ //TODO: properly process tabs
+ text = text.replace('\t', ' ');
+ text = text.replace((char)160, ' ');
+
AttributedString at = new AttributedString(text);
RichTextRun[] rt = txrun.getRichTextRuns();
for (int i = 0; i < rt.length; i++) {
@@ -109,7 +121,24 @@ public class TextPainter {
}
float wrappingWidth = (float)anchor.getWidth() - _shape.getMarginLeft() - _shape.getMarginRight();
- wrappingWidth -= rt.getTextOffset();
+ int bulletOffset = rt.getBulletOffset();
+ int textOffset = rt.getTextOffset();
+ int indent = rt.getIndentLevel();
+
+ TextRulerAtom ruler = run.getTextRuler();
+ if(ruler != null) {
+ int bullet_val = ruler.getBulletOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;
+ int text_val = ruler.getTextOffsets()[indent]*Shape.POINT_DPI/Shape.MASTER_DPI;
+ if(bullet_val > text_val){
+ int a = bullet_val;
+ bullet_val = text_val;
+ text_val = a;
+ }
+ if(bullet_val != 0 ) bulletOffset = bullet_val;
+ if(text_val != 0) textOffset = text_val;
+ }
+
+ wrappingWidth -= textOffset;
if (_shape.getWordWrap() == TextShape.WrapNone) {
wrappingWidth = _shape.getSheet().getSlideShow().getPageSize().width;
@@ -141,8 +170,9 @@ public class TextPainter {
}
el._align = rt.getAlignment();
- el._text = textLayout;
- el._textOffset = rt.getTextOffset();
+ el.advance = textLayout.getAdvance();
+ el._textOffset = textOffset;
+ el._text = new AttributedString(it, startIndex, endIndex);
if (prStart){
int sp = rt.getSpaceBefore();
@@ -182,13 +212,25 @@ public class TextPainter {
Color clr = rt.getBulletColor();
if (clr != null) bat.addAttribute(TextAttribute.FOREGROUND, clr);
else bat.addAttribute(TextAttribute.FOREGROUND, it.getAttribute(TextAttribute.FOREGROUND));
- bat.addAttribute(TextAttribute.FAMILY, it.getAttribute(TextAttribute.FAMILY));
- bat.addAttribute(TextAttribute.SIZE, it.getAttribute(TextAttribute.SIZE));
- TextLayout bulletLayout = new TextLayout(bat.getIterator(), graphics.getFontRenderContext());
+ int fontIdx = rt.getBulletFont();
+ if(fontIdx == -1) fontIdx = rt.getFontIndex();
+ PPFont bulletFont = _shape.getSheet().getSlideShow().getFont(fontIdx);
+ bat.addAttribute(TextAttribute.FAMILY, bulletFont.getFontName());
+
+ int bulletSize = rt.getBulletSize();
+ int fontSize = rt.getFontSize();
+ if(bulletSize != -1) fontSize = Math.round(fontSize*bulletSize*0.01f);
+ bat.addAttribute(TextAttribute.SIZE, new Float(fontSize));
+
+ if(!new Font(bulletFont.getFontName(), Font.PLAIN, 1).canDisplay(rt.getBulletChar())){
+ bat.addAttribute(TextAttribute.FAMILY, "Arial");
+ bat = new AttributedString("" + DEFAULT_BULLET_CHAR, bat.getIterator().getAttributes());
+ }
+
if(text.substring(startIndex, endIndex).length() > 1){
- el._bullet = bulletLayout;
- el._bulletOffset = rt.getBulletOffset();
+ el._bullet = bat;
+ el._bulletOffset = bulletOffset;
}
}
lines.add(el);
@@ -225,29 +267,32 @@ public class TextPainter {
break;
case TextShape.AlignCenter:
pen.x = anchor.getX() + _shape.getMarginLeft() +
- (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
+ (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight()) / 2;
break;
case TextShape.AlignRight:
pen.x = anchor.getX() + _shape.getMarginLeft() +
- (anchor.getWidth() - elem._text.getAdvance() - _shape.getMarginLeft() - _shape.getMarginRight());
+ (anchor.getWidth() - elem.advance - _shape.getMarginLeft() - _shape.getMarginRight());
break;
}
if(elem._bullet != null){
- elem._bullet.draw(graphics, (float)(pen.x + elem._bulletOffset), (float)pen.y);
+ graphics.drawString(elem._bullet.getIterator(), (float)(pen.x + elem._bulletOffset), (float)pen.y);
+ }
+ AttributedCharacterIterator chIt = elem._text.getIterator();
+ if(chIt.getEndIndex() > chIt.getBeginIndex()) {
+ graphics.drawString(chIt, (float)(pen.x + elem._textOffset), (float)pen.y);
}
- elem._text.draw(graphics, (float)(pen.x + elem._textOffset), (float)pen.y);
-
y0 += elem.descent;
}
}
- static class TextElement {
- public TextLayout _text;
+ public static class TextElement {
+ public AttributedString _text;
public int _textOffset;
- public TextLayout _bullet;
+ public AttributedString _bullet;
public int _bulletOffset;
public int _align;
public float ascent, descent;
+ public float advance;
}
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
index 2f77ac5ff..5dac65025 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
@@ -535,9 +535,13 @@ public class TextRun
// them to \n
String text = rawText.replace('\r','\n');
- //0xB acts like cariage return in page titles
- text = text.replace((char) 0x0B, '\n');
-
+ int type = _headerAtom == null ? 0 : _headerAtom.getTextType();
+ if(type == TextHeaderAtom.TITLE_TYPE || type == TextHeaderAtom.CENTER_TITLE_TYPE){
+ //0xB acts like cariage return in page titles and like blank in the others
+ text = text.replace((char) 0x0B, '\n');
+ } else {
+ text = text.replace((char) 0x0B, ' ');
+ }
return text;
}
@@ -655,4 +659,11 @@ public class TextRun
return null;
}
+ public TextRulerAtom getTextRuler(){
+ for (int i = 0; i < _records.length; i++) {
+ if(_records[i] instanceof TextRulerAtom) return (TextRulerAtom)_records[i];
+ }
+ return null;
+
+ }
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
index 7249817be..53f8ef97d 100755
--- a/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextShape.java
@@ -261,17 +261,28 @@ public abstract class TextShape extends SimpleShape {
public int getVerticalAlignment(){
EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID);
EscherSimpleProperty prop = (EscherSimpleProperty)getEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT);
- int valign;
+ int valign = TextShape.AnchorTop;
if (prop == null){
+ /**
+ * If vertical alignment was not found in the shape properties then try to
+ * fetch the master shape and search for the align property there.
+ */
int type = getTextRun().getRunType();
- switch (type){
- case TextHeaderAtom.TITLE_TYPE:
- case TextHeaderAtom.CENTER_TITLE_TYPE:
- valign = TextShape.AnchorMiddle;
- break;
- default:
- valign = TextShape.AnchorTop;
- break;
+ MasterSheet master = getSheet().getMasterSheet();
+ if(master != null){
+ TextShape masterShape = master.getPlaceholder(type);
+ if(masterShape != null) valign = masterShape.getVerticalAlignment();
+ } else {
+ //not found in the master sheet. Use the hardcoded defaults.
+ switch (type){
+ case TextHeaderAtom.TITLE_TYPE:
+ case TextHeaderAtom.CENTER_TITLE_TYPE:
+ valign = TextShape.AnchorMiddle;
+ break;
+ default:
+ valign = TextShape.AnchorTop;
+ break;
+ }
}
} else {
valign = prop.getPropertyValue();
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
index e42b358b8..3a1ed8dbe 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java
@@ -24,11 +24,13 @@ import org.apache.poi.util.POILogger;
import org.apache.poi.ddf.*;
import org.apache.poi.hslf.model.ShapeTypes;
+import org.apache.poi.hslf.model.Shape;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import java.util.Vector;
+import java.util.Iterator;
/**
* These are actually wrappers onto Escher drawings. Make use of
@@ -52,6 +54,8 @@ public class PPDrawing extends RecordAtom
private EscherRecord[] childRecords;
private EscherTextboxWrapper[] textboxWrappers;
+ //cached EscherDgRecord
+ private EscherDgRecord dg;
/**
* Get access to the underlying Escher Records
@@ -296,4 +300,24 @@ public class PPDrawing extends RecordAtom
tw[textboxWrappers.length] = txtbox;
textboxWrappers = tw;
}
+
+ /**
+ * Return EscherDgRecord which keeps track of the number of shapes and shapeId in this drawing group
+ *
+ * @return EscherDgRecord
+ */
+ public EscherDgRecord getEscherDgRecord(){
+ if(dg == null){
+ EscherContainerRecord dgContainer = (EscherContainerRecord)childRecords[0];
+ for(Iterator it = dgContainer.getChildRecords().iterator(); it.hasNext();){
+ EscherRecord r = (EscherRecord) it.next();
+ if(r instanceof EscherDgRecord){
+ dg = (EscherDgRecord)r;
+ break;
+ }
+ }
+ }
+ return dg;
+ }
+
}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
index 45038f7a2..cedc99ce0 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java
@@ -89,7 +89,7 @@ public class RecordTypes {
public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
public static final Type TxCFStyleAtom = new Type(4004,null);
public static final Type TxPFStyleAtom = new Type(4005,null);
- public static final Type TextRulerAtom = new Type(4006,null);
+ public static final Type TextRulerAtom = new Type(4006,TextRulerAtom.class);
public static final Type TextBookmarkAtom = new Type(4007,null);
public static final Type TextBytesAtom = new Type(4008,TextBytesAtom.class);
public static final Type TxSIStyleAtom = new Type(4009,null);
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
index 187dec12a..2f3b898a7 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
@@ -127,8 +127,8 @@ public class StyleTextPropAtom extends RecordAtom
new ParagraphFlagsTextProp(),
new TextProp(2, 0x80, "bullet.char"),
new TextProp(2, 0x10, "bullet.font"),
+ new TextProp(2, 0x40, "bullet.size"),
new TextProp(4, 0x20, "bullet.color"),
- new TextProp(2, 0x40, "bullet.size"),
new AlignmentTextProp(),
new TextProp(2, 0x100, "text.offset"),
new TextProp(2, 0x200, "para_unknown_2"),
diff --git a/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java b/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
new file mode 100755
index 000000000..71ded8540
--- /dev/null
+++ b/src/scratchpad/src/org/apache/poi/hslf/record/TextRulerAtom.java
@@ -0,0 +1,194 @@
+/* ====================================================================
+ 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.record;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.InflaterInputStream;
+
+import org.apache.poi.util.LittleEndian;
+import org.apache.poi.util.POILogger;
+
+/**
+ * Ruler of a text as it differs from the style's ruler settings.
+ *
+ * @author Yegor Kozlov
+ */
+public class TextRulerAtom extends RecordAtom {
+
+ /**
+ * Record header.
+ */
+ private byte[] _header;
+
+ /**
+ * Record data.
+ */
+ private byte[] _data;
+
+ //ruler internals
+ private int defaultTabSize;
+ private int numLevels;
+ private int[] tabStops;
+ private int[] bulletOffsets = new int[5];
+ private int[] textOffsets = new int[5];
+
+ /**
+ * Constructs a new empty ruler atom.
+ */
+ protected TextRulerAtom() {
+ _header = new byte[8];
+ _data = new byte[0];
+
+ LittleEndian.putShort(_header, 2, (short)getRecordType());
+ LittleEndian.putInt(_header, 4, _data.length);
+ }
+
+ /**
+ * Constructs the ruler atom record from its
+ * source data.
+ *
+ * @param source the source data as a byte array.
+ * @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 = new byte[len-8];
+ System.arraycopy(source,start+8,_data,0,len-8);
+
+ try {
+ read();
+ } catch (Exception e){
+ logger.log(POILogger.ERROR, "Failed to parse TextRulerAtom: " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets the record type.
+ *
+ * @return the record type.
+ */
+ public long getRecordType() {
+ return RecordTypes.TextRulerAtom.typeID;
+ }
+
+ /**
+ * Write the contents of the record back, so it can be written
+ * to disk.
+ *
+ * @param out the output stream to write to.
+ * @throws java.io.IOException if an error occurs.
+ */
+ public void writeOut(OutputStream out) throws IOException {
+ out.write(_header);
+ out.write(_data);
+ }
+
+ /**
+ * 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 distance between tab stops, in master coordinates (576 dpi).
+ */
+ public int getDefaultTabSize(){
+ return defaultTabSize;
+ }
+
+ /**
+ * Number of indent levels (maximum 5).
+ */
+ public int getNumberOfLevels(){
+ return numLevels;
+ }
+
+ /**
+ * Default distance between tab stops, in master coordinates (576 dpi).
+ */
+ public int[] getTabStops(){
+ return tabStops;
+ }
+
+ /**
+ * Paragraph's distance from shape's left margin, in master coordinates (576 dpi).
+ */
+ public int[] getTextOffsets(){
+ return textOffsets;
+ }
+
+ /**
+ * First line of paragraph's distance from shape's left margin, in master coordinates (576 dpi).
+ */
+ public int[] getBulletOffsets(){
+ return bulletOffsets;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
index 2a09f2224..7458df7e6 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
@@ -32,6 +32,8 @@ import org.apache.poi.hslf.model.textproperties.ParagraphFlagsTextProp;
import org.apache.poi.hslf.model.textproperties.TextProp;
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
import org.apache.poi.hslf.record.ColorSchemeAtom;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.util.POILogFactory;
/**
@@ -39,6 +41,8 @@ import org.apache.poi.hslf.record.ColorSchemeAtom;
*
*/
public class RichTextRun {
+ protected POILogger logger = POILogFactory.getLogger(this.getClass());
+
/** The TextRun we belong to */
private TextRun parentRun;
/** The SlideShow we belong to */
@@ -199,10 +203,15 @@ public class RichTextRun {
}
if (prop == null){
Sheet sheet = parentRun.getSheet();
- int txtype = parentRun.getRunType();
- MasterSheet master = sheet.getMasterSheet();
- if (master != null)
- prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
+ if(sheet != null){
+ int txtype = parentRun.getRunType();
+ MasterSheet master = sheet.getMasterSheet();
+ if (master != null){
+ prop = (BitMaskTextProp)master.getStyleAttribute(txtype, getIndentLevel(), propname, isCharacter);
+ }
+ } else {
+ logger.log(POILogger.WARN, "MasterSheet is not available");
+ }
}
return prop == null ? false : prop.getSubValue(index);
@@ -213,7 +222,7 @@ public class RichTextRun {
* it if required.
*/
private void setCharFlagsTextPropVal(int index, boolean value) {
- setFlag(true, index, value);
+ if(getFlag(true, index) != value) setFlag(true, index, value);
}
public void setFlag(boolean isCharacter, int index, boolean value) {
@@ -281,10 +290,14 @@ public class RichTextRun {
*/
private int getParaTextPropVal(String propName) {
TextProp prop = null;
+ boolean hardAttribute = false;
if (paragraphStyle != null){
prop = paragraphStyle.findByName(propName);
+
+ BitMaskTextProp maskProp = (BitMaskTextProp)paragraphStyle.findByName(ParagraphFlagsTextProp.NAME);
+ hardAttribute = maskProp != null && maskProp.getValue() == 0;
}
- if (prop == null){
+ if (prop == null && !hardAttribute){
Sheet sheet = parentRun.getSheet();
int txtype = parentRun.getRunType();
MasterSheet master = sheet.getMasterSheet();
@@ -574,6 +587,13 @@ public class RichTextRun {
return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
}
+ /**
+ * Returns whether this rich text run has bullets
+ */
+ public boolean isBulletHard() {
+ return getFlag(false, ParagraphFlagsTextProp.BULLET_IDX);
+ }
+
/**
* Sets the bullet character
*/
diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
index 828255087..d969c5b88 100644
--- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
+++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
@@ -24,10 +24,7 @@ import java.util.*;
import java.awt.Dimension;
import java.io.*;
-import org.apache.poi.ddf.EscherBSERecord;
-import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherOptRecord;
-import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.*;
import org.apache.poi.hslf.*;
import org.apache.poi.hslf.model.*;
import org.apache.poi.hslf.model.Notes;
@@ -66,9 +63,7 @@ public class SlideShow
// Lookup between the PersitPtr "sheet" IDs, and the position
// in the mostRecentCoreRecords array
private Hashtable _sheetIdToCoreRecordsLookup;
- // Used when adding new core records
- private int _highestSheetId;
-
+
// Records that are interesting
private Document _documentRecord;
@@ -203,8 +198,6 @@ public class SlideShow
for(int i=0; i