#57796 - Support hyperlink extraction when rendering slides
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724338 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ef61211207
commit
b0c16b8261
@ -46,7 +46,7 @@ public abstract class CreateHyperlink {
|
|||||||
String text = textBox1.getText();
|
String text = textBox1.getText();
|
||||||
HSLFHyperlink link = new HSLFHyperlink();
|
HSLFHyperlink link = new HSLFHyperlink();
|
||||||
link.setAddress("http://www.apache.org");
|
link.setAddress("http://www.apache.org");
|
||||||
link.setTitle(textBox1.getText());
|
link.setLabel(textBox1.getText());
|
||||||
int linkId = ppt.addHyperlink(link);
|
int linkId = ppt.addHyperlink(link);
|
||||||
|
|
||||||
// apply link to the text
|
// apply link to the text
|
||||||
|
@ -70,6 +70,6 @@ public final class Hyperlinks {
|
|||||||
//in ppt end index is inclusive
|
//in ppt end index is inclusive
|
||||||
String formatStr = "title: %1$s, address: %2$s" + (rawText == null ? "" : ", start: %3$s, end: %4$s, substring: %5$s");
|
String formatStr = "title: %1$s, address: %2$s" + (rawText == null ? "" : ", start: %3$s, end: %4$s, substring: %5$s");
|
||||||
String substring = (rawText == null) ? "" : rawText.substring(link.getStartIndex(), link.getEndIndex()-1);
|
String substring = (rawText == null) ? "" : rawText.substring(link.getStartIndex(), link.getEndIndex()-1);
|
||||||
return String.format(formatStr, link.getTitle(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), substring);
|
return String.format(formatStr, link.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), substring);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ import java.awt.font.LineBreakMeasurer;
|
|||||||
import java.awt.font.TextAttribute;
|
import java.awt.font.TextAttribute;
|
||||||
import java.awt.font.TextLayout;
|
import java.awt.font.TextLayout;
|
||||||
import java.awt.geom.Rectangle2D;
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import java.io.InvalidObjectException;
|
||||||
import java.text.AttributedCharacterIterator;
|
import java.text.AttributedCharacterIterator;
|
||||||
import java.text.AttributedCharacterIterator.Attribute;
|
import java.text.AttributedCharacterIterator.Attribute;
|
||||||
import java.text.AttributedString;
|
import java.text.AttributedString;
|
||||||
@ -32,6 +33,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
|
import org.apache.poi.sl.usermodel.AutoNumberingScheme;
|
||||||
|
import org.apache.poi.sl.usermodel.Hyperlink;
|
||||||
import org.apache.poi.sl.usermodel.Insets2D;
|
import org.apache.poi.sl.usermodel.Insets2D;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||||
import org.apache.poi.sl.usermodel.PlaceableShape;
|
import org.apache.poi.sl.usermodel.PlaceableShape;
|
||||||
@ -46,6 +48,10 @@ import org.apache.poi.util.StringUtil;
|
|||||||
import org.apache.poi.util.Units;
|
import org.apache.poi.util.Units;
|
||||||
|
|
||||||
public class DrawTextParagraph implements Drawable {
|
public class DrawTextParagraph implements Drawable {
|
||||||
|
/** Keys for passing hyperlinks to the graphics context */
|
||||||
|
public static final XlinkAttribute HYPERLINK_HREF = new XlinkAttribute("href");
|
||||||
|
public static final XlinkAttribute HYPERLINK_LABEL = new XlinkAttribute("label");
|
||||||
|
|
||||||
protected TextParagraph<?,?,?> paragraph;
|
protected TextParagraph<?,?,?> paragraph;
|
||||||
double x, y;
|
double x, y;
|
||||||
protected List<DrawTextFragment> lines = new ArrayList<DrawTextFragment>();
|
protected List<DrawTextFragment> lines = new ArrayList<DrawTextFragment>();
|
||||||
@ -58,6 +64,31 @@ public class DrawTextParagraph implements Drawable {
|
|||||||
*/
|
*/
|
||||||
protected double maxLineHeight;
|
protected double maxLineHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines an attribute used for storing the hyperlink associated with
|
||||||
|
* some renderable text.
|
||||||
|
*/
|
||||||
|
private static class XlinkAttribute extends Attribute {
|
||||||
|
|
||||||
|
XlinkAttribute(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolves instances being deserialized to the predefined constants.
|
||||||
|
*/
|
||||||
|
protected Object readResolve() throws InvalidObjectException {
|
||||||
|
if (HYPERLINK_HREF.getName().equals(getName())) {
|
||||||
|
return HYPERLINK_HREF;
|
||||||
|
}
|
||||||
|
if (HYPERLINK_LABEL.getName().equals(getName())) {
|
||||||
|
return HYPERLINK_LABEL;
|
||||||
|
}
|
||||||
|
throw new InvalidObjectException("unknown attribute name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public DrawTextParagraph(TextParagraph<?,?,?> paragraph) {
|
public DrawTextParagraph(TextParagraph<?,?,?> paragraph) {
|
||||||
this.paragraph = paragraph;
|
this.paragraph = paragraph;
|
||||||
}
|
}
|
||||||
@ -498,6 +529,12 @@ public class DrawTextParagraph implements Drawable {
|
|||||||
if(run.isSuperscript()) {
|
if(run.isSuperscript()) {
|
||||||
attList.add(new AttributedStringData(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, beginIndex, endIndex));
|
attList.add(new AttributedStringData(TextAttribute.SUPERSCRIPT, TextAttribute.SUPERSCRIPT_SUPER, beginIndex, endIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Hyperlink hl = run.getHyperlink();
|
||||||
|
if (hl != null) {
|
||||||
|
attList.add(new AttributedStringData(HYPERLINK_HREF, hl.getAddress(), beginIndex, endIndex));
|
||||||
|
attList.add(new AttributedStringData(HYPERLINK_LABEL, hl.getLabel(), beginIndex, endIndex));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure that the paragraph contains at least one character
|
// ensure that the paragraph contains at least one character
|
||||||
|
@ -156,4 +156,11 @@ public interface TextRun {
|
|||||||
* @return the pitch and family id or -1 if not applicable
|
* @return the pitch and family id or -1 if not applicable
|
||||||
*/
|
*/
|
||||||
byte getPitchAndFamily();
|
byte getPitchAndFamily();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the associated hyperlink
|
||||||
|
*
|
||||||
|
* @return the associated hyperlink or null if no hyperlink was set
|
||||||
|
*/
|
||||||
|
Hyperlink getHyperlink();
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,13 @@ package org.apache.poi.xslf.usermodel;
|
|||||||
|
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
import org.apache.poi.openxml4j.opc.TargetMode;
|
import org.apache.poi.openxml4j.opc.TargetMode;
|
||||||
|
import org.apache.poi.sl.usermodel.Hyperlink;
|
||||||
import org.apache.poi.util.Internal;
|
import org.apache.poi.util.Internal;
|
||||||
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
|
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
/**
|
public class XSLFHyperlink implements Hyperlink {
|
||||||
* @author Yegor Kozlov
|
|
||||||
*/
|
|
||||||
public class XSLFHyperlink {
|
|
||||||
final XSLFTextRun _r;
|
final XSLFTextRun _r;
|
||||||
final CTHyperlink _link;
|
final CTHyperlink _link;
|
||||||
|
|
||||||
@ -40,13 +38,37 @@ public class XSLFHyperlink {
|
|||||||
return _link;
|
return _link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setAddress(String address){
|
public void setAddress(String address){
|
||||||
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
|
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
|
||||||
PackageRelationship rel =
|
PackageRelationship rel =
|
||||||
sheet.getPackagePart().
|
sheet.getPackagePart().
|
||||||
addExternalRelationship(address, XSLFRelation.HYPERLINK.getRelation());
|
addExternalRelationship(address, XSLFRelation.HYPERLINK.getRelation());
|
||||||
_link.setId(rel.getId());
|
_link.setId(rel.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAddress() {
|
||||||
|
return getTargetURI().toASCIIString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getLabel() {
|
||||||
|
return _link.getTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setLabel(String label) {
|
||||||
|
_link.setTooltip(label);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getType() {
|
||||||
|
// TODO: currently this just returns nonsense
|
||||||
|
if ("ppaction://hlinksldjump".equals(_link.getAction())) {
|
||||||
|
return LINK_DOCUMENT;
|
||||||
|
}
|
||||||
|
return LINK_URL;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setAddress(XSLFSlide slide){
|
public void setAddress(XSLFSlide slide){
|
||||||
|
@ -449,6 +449,7 @@ public class XSLFTextRun implements TextRun {
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public XSLFHyperlink getHyperlink(){
|
public XSLFHyperlink getHyperlink(){
|
||||||
if(!_r.getRPr().isSetHlinkClick()) return null;
|
if(!_r.getRPr().isSetHlinkClick()) return null;
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable {
|
|||||||
*/
|
*/
|
||||||
public void drawString(String s, float x, float y) {
|
public void drawString(String s, float x, float y) {
|
||||||
HSLFTextBox txt = new HSLFTextBox(_group);
|
HSLFTextBox txt = new HSLFTextBox(_group);
|
||||||
txt.getTextParagraphs().get(0).supplySheet(_group.getSheet());
|
txt.setSheet(_group.getSheet());
|
||||||
txt.setText(s);
|
txt.setText(s);
|
||||||
|
|
||||||
HSLFTextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0);
|
HSLFTextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0);
|
||||||
|
@ -29,13 +29,12 @@ import org.apache.poi.hslf.record.InteractiveInfo;
|
|||||||
import org.apache.poi.hslf.record.InteractiveInfoAtom;
|
import org.apache.poi.hslf.record.InteractiveInfoAtom;
|
||||||
import org.apache.poi.hslf.record.Record;
|
import org.apache.poi.hslf.record.Record;
|
||||||
import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
|
import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
|
||||||
|
import org.apache.poi.sl.usermodel.Hyperlink;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a hyperlink in a PowerPoint document
|
* Represents a hyperlink in a PowerPoint document
|
||||||
*
|
|
||||||
* @author Yegor Kozlov
|
|
||||||
*/
|
*/
|
||||||
public final class HSLFHyperlink {
|
public final class HSLFHyperlink implements Hyperlink {
|
||||||
public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide;
|
public static final byte LINK_NEXTSLIDE = InteractiveInfoAtom.LINK_NextSlide;
|
||||||
public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide;
|
public static final byte LINK_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide;
|
||||||
public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide;
|
public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide;
|
||||||
@ -47,7 +46,7 @@ public final class HSLFHyperlink {
|
|||||||
private int id=-1;
|
private int id=-1;
|
||||||
private int type;
|
private int type;
|
||||||
private String address;
|
private String address;
|
||||||
private String title;
|
private String label;
|
||||||
private int startIndex, endIndex;
|
private int startIndex, endIndex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,6 +56,7 @@ public final class HSLFHyperlink {
|
|||||||
* @return the hyperlink URL
|
* @return the hyperlink URL
|
||||||
* @see InteractiveInfoAtom
|
* @see InteractiveInfoAtom
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
public int getType() {
|
public int getType() {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -65,35 +65,31 @@ public final class HSLFHyperlink {
|
|||||||
type = val;
|
type = val;
|
||||||
switch(type){
|
switch(type){
|
||||||
case LINK_NEXTSLIDE:
|
case LINK_NEXTSLIDE:
|
||||||
title = "NEXT";
|
label = "NEXT";
|
||||||
address = "1,-1,NEXT";
|
address = "1,-1,NEXT";
|
||||||
break;
|
break;
|
||||||
case LINK_PREVIOUSSLIDE:
|
case LINK_PREVIOUSSLIDE:
|
||||||
title = "PREV";
|
label = "PREV";
|
||||||
address = "1,-1,PREV";
|
address = "1,-1,PREV";
|
||||||
break;
|
break;
|
||||||
case LINK_FIRSTSLIDE:
|
case LINK_FIRSTSLIDE:
|
||||||
title = "FIRST";
|
label = "FIRST";
|
||||||
address = "1,-1,FIRST";
|
address = "1,-1,FIRST";
|
||||||
break;
|
break;
|
||||||
case LINK_LASTSLIDE:
|
case LINK_LASTSLIDE:
|
||||||
title = "LAST";
|
label = "LAST";
|
||||||
address = "1,-1,LAST";
|
address = "1,-1,LAST";
|
||||||
break;
|
break;
|
||||||
case LINK_SLIDENUMBER:
|
case LINK_SLIDENUMBER:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
title = "";
|
label = "";
|
||||||
address = "";
|
address = "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the hyperlink URL
|
|
||||||
*
|
|
||||||
* @return the hyperlink URL
|
|
||||||
*/
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
@ -101,10 +97,11 @@ public final class HSLFHyperlink {
|
|||||||
public void setAddress(HSLFSlide slide) {
|
public void setAddress(HSLFSlide slide) {
|
||||||
String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber();
|
String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber();
|
||||||
setAddress(href);;
|
setAddress(href);;
|
||||||
setTitle("Slide " + slide.getSlideNumber());
|
setLabel("Slide " + slide.getSlideNumber());
|
||||||
setType(HSLFHyperlink.LINK_SLIDENUMBER);
|
setType(HSLFHyperlink.LINK_SLIDENUMBER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void setAddress(String str) {
|
public void setAddress(String str) {
|
||||||
address = str;
|
address = str;
|
||||||
}
|
}
|
||||||
@ -117,17 +114,14 @@ public final class HSLFHyperlink {
|
|||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Gets the hyperlink user-friendly title (if different from URL)
|
public String getLabel() {
|
||||||
*
|
return label;
|
||||||
* @return the hyperlink user-friendly title
|
|
||||||
*/
|
|
||||||
public String getTitle() {
|
|
||||||
return title;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setTitle(String str) {
|
@Override
|
||||||
title = str;
|
public void setLabel(String str) {
|
||||||
|
label = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -139,6 +133,15 @@ public final class HSLFHyperlink {
|
|||||||
return startIndex;
|
return startIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the beginning character position
|
||||||
|
*
|
||||||
|
* @param startIndex the beginning character position
|
||||||
|
*/
|
||||||
|
public void setStartIndex(int startIndex) {
|
||||||
|
this.startIndex = startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the ending character position
|
* Gets the ending character position
|
||||||
*
|
*
|
||||||
@ -148,6 +151,15 @@ public final class HSLFHyperlink {
|
|||||||
return endIndex;
|
return endIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ending character position
|
||||||
|
*
|
||||||
|
* @param endIndex the ending character position
|
||||||
|
*/
|
||||||
|
public void setEndIndex(int endIndex) {
|
||||||
|
this.endIndex = endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find hyperlinks in a text shape
|
* Find hyperlinks in a text shape
|
||||||
*
|
*
|
||||||
@ -222,9 +234,10 @@ public final class HSLFHyperlink {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HSLFHyperlink link = new HSLFHyperlink();
|
HSLFHyperlink link = new HSLFHyperlink();
|
||||||
link.title = linkRecord.getLinkTitle();
|
link.setId(id);
|
||||||
link.address = linkRecord.getLinkURL();
|
link.setType(info.getAction());
|
||||||
link.type = info.getAction();
|
link.setLabel(linkRecord.getLinkTitle());
|
||||||
|
link.setAddress(linkRecord.getLinkURL());
|
||||||
out.add(link);
|
out.add(link);
|
||||||
|
|
||||||
if (iter.hasNext()) {
|
if (iter.hasNext()) {
|
||||||
@ -234,8 +247,8 @@ public final class HSLFHyperlink {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)r;
|
TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)r;
|
||||||
link.startIndex = txinfo.getStartIndex();
|
link.setStartIndex(txinfo.getStartIndex());
|
||||||
link.endIndex = txinfo.getEndIndex();
|
link.setEndIndex(txinfo.getEndIndex());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -56,13 +56,6 @@ public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape,HSLFTe
|
|||||||
if (_paragraphs.isEmpty()) {
|
if (_paragraphs.isEmpty()) {
|
||||||
logger.log(POILogger.WARN, "No text records found for notes sheet");
|
logger.log(POILogger.WARN, "No text records found for notes sheet");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the sheet on each TextRun
|
|
||||||
for (List<HSLFTextParagraph> ltp : _paragraphs) {
|
|
||||||
for (HSLFTextParagraph tp : ltp) {
|
|
||||||
tp.supplySheet(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -133,9 +133,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
|
|||||||
List<List<HSLFTextParagraph>> trs = getTextParagraphs();
|
List<List<HSLFTextParagraph>> trs = getTextParagraphs();
|
||||||
if (trs == null) return;
|
if (trs == null) return;
|
||||||
for (List<HSLFTextParagraph> ltp : trs) {
|
for (List<HSLFTextParagraph> ltp : trs) {
|
||||||
for (HSLFTextParagraph tp : ltp) {
|
HSLFTextParagraph.supplySheet(ltp, this);
|
||||||
tp.supplySheet(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H
|
|||||||
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber);
|
infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.log(POILogger.WARN, "Ignore unknown hyperlink type : "+link.getTitle());
|
logger.log(POILogger.WARN, "Ignore unknown hyperlink type : "+link.getLabel());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,12 +94,6 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
|
|||||||
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
|
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
|
||||||
if (!_paragraphs.contains(l)) _paragraphs.add(l);
|
if (!_paragraphs.contains(l)) _paragraphs.add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(List<HSLFTextParagraph> ltp : _paragraphs) {
|
|
||||||
for (HSLFTextParagraph tp : ltp) {
|
|
||||||
tp.supplySheet(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,12 +51,6 @@ public final class HSLFSlideMaster extends HSLFMasterSheet {
|
|||||||
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
|
for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) {
|
||||||
if (!_paragraphs.contains(l)) _paragraphs.add(l);
|
if (!_paragraphs.contains(l)) _paragraphs.add(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (List<HSLFTextParagraph> p : _paragraphs) {
|
|
||||||
for (HSLFTextParagraph htp : p) {
|
|
||||||
htp.supplySheet(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,6 +33,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.record.MainMaster;
|
||||||
import org.apache.poi.ddf.EscherBSERecord;
|
import org.apache.poi.ddf.EscherBSERecord;
|
||||||
import org.apache.poi.ddf.EscherContainerRecord;
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
import org.apache.poi.ddf.EscherOptRecord;
|
import org.apache.poi.ddf.EscherOptRecord;
|
||||||
@ -59,12 +60,14 @@ import org.apache.poi.hslf.record.ExVideoContainer;
|
|||||||
import org.apache.poi.hslf.record.FontCollection;
|
import org.apache.poi.hslf.record.FontCollection;
|
||||||
import org.apache.poi.hslf.record.FontEntityAtom;
|
import org.apache.poi.hslf.record.FontEntityAtom;
|
||||||
import org.apache.poi.hslf.record.HeadersFootersContainer;
|
import org.apache.poi.hslf.record.HeadersFootersContainer;
|
||||||
|
import org.apache.poi.hslf.record.Notes;
|
||||||
import org.apache.poi.hslf.record.PersistPtrHolder;
|
import org.apache.poi.hslf.record.PersistPtrHolder;
|
||||||
import org.apache.poi.hslf.record.PositionDependentRecord;
|
import org.apache.poi.hslf.record.PositionDependentRecord;
|
||||||
import org.apache.poi.hslf.record.PositionDependentRecordContainer;
|
import org.apache.poi.hslf.record.PositionDependentRecordContainer;
|
||||||
import org.apache.poi.hslf.record.Record;
|
import org.apache.poi.hslf.record.Record;
|
||||||
import org.apache.poi.hslf.record.RecordContainer;
|
import org.apache.poi.hslf.record.RecordContainer;
|
||||||
import org.apache.poi.hslf.record.RecordTypes;
|
import org.apache.poi.hslf.record.RecordTypes;
|
||||||
|
import org.apache.poi.hslf.record.Slide;
|
||||||
import org.apache.poi.hslf.record.SlideListWithText;
|
import org.apache.poi.hslf.record.SlideListWithText;
|
||||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||||
import org.apache.poi.hslf.record.SlidePersistAtom;
|
import org.apache.poi.hslf.record.SlidePersistAtom;
|
||||||
@ -120,12 +123,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
private POILogger logger = POILogFactory.getLogger(this.getClass());
|
private POILogger logger = POILogFactory.getLogger(this.getClass());
|
||||||
|
|
||||||
|
|
||||||
/* ===============================================================
|
|
||||||
* Setup Code
|
|
||||||
* ===============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Powerpoint document from the underlying
|
* Constructs a Powerpoint document from the underlying
|
||||||
* HSLFSlideShow object. Finds the model stuff from this
|
* HSLFSlideShow object. Finds the model stuff from this
|
||||||
@ -338,136 +335,131 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
// We always use the latest versions of these records, and use the
|
// We always use the latest versions of these records, and use the
|
||||||
// SlideAtom/NotesAtom to match them with the StyleAtomSet
|
// SlideAtom/NotesAtom to match them with the StyleAtomSet
|
||||||
|
|
||||||
SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText();
|
findMasterSlides();
|
||||||
SlideListWithText slidesSLWT = _documentRecord.getSlideSlideListWithText();
|
|
||||||
SlideListWithText notesSLWT = _documentRecord.getNotesSlideListWithText();
|
|
||||||
|
|
||||||
// Find master slides
|
|
||||||
// These can be MainMaster records, but oddly they can also be
|
|
||||||
// Slides or Notes, and possibly even other odd stuff....
|
|
||||||
// About the only thing you can say is that the master details are in
|
|
||||||
// the first SLWT.
|
|
||||||
if (masterSLWT != null) {
|
|
||||||
for (SlideAtomsSet sas : masterSLWT.getSlideAtomsSets()) {
|
|
||||||
Record r = getCoreRecordForSAS(sas);
|
|
||||||
int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier();
|
|
||||||
if (r instanceof org.apache.poi.hslf.record.Slide) {
|
|
||||||
HSLFTitleMaster master = new HSLFTitleMaster((org.apache.poi.hslf.record.Slide) r,
|
|
||||||
sheetNo);
|
|
||||||
master.setSlideShow(this);
|
|
||||||
_titleMasters.add(master);
|
|
||||||
} else if (r instanceof org.apache.poi.hslf.record.MainMaster) {
|
|
||||||
HSLFSlideMaster master = new HSLFSlideMaster((org.apache.poi.hslf.record.MainMaster) r,
|
|
||||||
sheetNo);
|
|
||||||
master.setSlideShow(this);
|
|
||||||
_masters.add(master);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Having sorted out the masters, that leaves the notes and slides
|
// Having sorted out the masters, that leaves the notes and slides
|
||||||
|
Map<Integer,Integer> slideIdToNotes = new HashMap<Integer,Integer>();
|
||||||
|
|
||||||
// Start by finding the notes records to go with the entries in
|
// Start by finding the notes records
|
||||||
// notesSLWT
|
findNotesSlides(slideIdToNotes);
|
||||||
org.apache.poi.hslf.record.Notes[] notesRecords;
|
|
||||||
Map<Integer,Integer> slideIdToNotes = new HashMap<Integer,Integer>();
|
|
||||||
if (notesSLWT == null) {
|
|
||||||
// None
|
|
||||||
notesRecords = new org.apache.poi.hslf.record.Notes[0];
|
|
||||||
} else {
|
|
||||||
// Match up the records and the SlideAtomSets
|
|
||||||
List<org.apache.poi.hslf.record.Notes> notesRecordsL =
|
|
||||||
new ArrayList<org.apache.poi.hslf.record.Notes>();
|
|
||||||
int idx = -1;
|
|
||||||
for (SlideAtomsSet notesSet : notesSLWT.getSlideAtomsSets()) {
|
|
||||||
idx++;
|
|
||||||
// Get the right core record
|
|
||||||
Record r = getCoreRecordForSAS(notesSet);
|
|
||||||
SlidePersistAtom spa = notesSet.getSlidePersistAtom();
|
|
||||||
|
|
||||||
String loggerLoc = "A Notes SlideAtomSet at "+idx+" said its record was at refID "+spa.getRefID();
|
|
||||||
|
|
||||||
// Ensure it really is a notes record
|
|
||||||
if (r == null || r instanceof org.apache.poi.hslf.record.Notes) {
|
|
||||||
if (r == null) {
|
|
||||||
logger.log(POILogger.WARN, loggerLoc+", but that record didn't exist - record ignored.");
|
|
||||||
}
|
|
||||||
// we need to add also null-records, otherwise the index references to other existing
|
|
||||||
// don't work anymore
|
|
||||||
org.apache.poi.hslf.record.Notes notesRecord = (org.apache.poi.hslf.record.Notes) r;
|
|
||||||
notesRecordsL.add(notesRecord);
|
|
||||||
|
|
||||||
// Record the match between slide id and these notes
|
|
||||||
int slideId = spa.getSlideIdentifier();
|
|
||||||
slideIdToNotes.put(slideId, idx);
|
|
||||||
} else {
|
|
||||||
logger.log(POILogger.ERROR, loggerLoc+", but that was actually a " + r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
notesRecords = new org.apache.poi.hslf.record.Notes[notesRecordsL.size()];
|
|
||||||
notesRecords = notesRecordsL.toArray(notesRecords);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, do the same thing for our slides
|
// Now, do the same thing for our slides
|
||||||
org.apache.poi.hslf.record.Slide[] slidesRecords;
|
findSlides(slideIdToNotes);
|
||||||
SlideAtomsSet[] slidesSets = new SlideAtomsSet[0];
|
}
|
||||||
if (slidesSLWT == null) {
|
|
||||||
// None
|
|
||||||
slidesRecords = new org.apache.poi.hslf.record.Slide[0];
|
|
||||||
} else {
|
|
||||||
// Match up the records and the SlideAtomSets
|
|
||||||
slidesSets = slidesSLWT.getSlideAtomsSets();
|
|
||||||
slidesRecords = new org.apache.poi.hslf.record.Slide[slidesSets.length];
|
|
||||||
for (int i = 0; i < slidesSets.length; i++) {
|
|
||||||
// Get the right core record
|
|
||||||
Record r = getCoreRecordForSAS(slidesSets[i]);
|
|
||||||
|
|
||||||
// Ensure it really is a slide record
|
/**
|
||||||
if (r instanceof org.apache.poi.hslf.record.Slide) {
|
* Find master slides
|
||||||
slidesRecords[i] = (org.apache.poi.hslf.record.Slide) r;
|
* These can be MainMaster records, but oddly they can also be
|
||||||
} else {
|
* Slides or Notes, and possibly even other odd stuff....
|
||||||
logger.log(POILogger.ERROR, "A Slide SlideAtomSet at " + i
|
* About the only thing you can say is that the master details are in the first SLWT.
|
||||||
+ " said its record was at refID "
|
*/
|
||||||
+ slidesSets[i].getSlidePersistAtom().getRefID()
|
private void findMasterSlides() {
|
||||||
+ ", but that was actually a " + r);
|
SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText();
|
||||||
}
|
if (masterSLWT == null) {
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, generate model objects for everything
|
for (SlideAtomsSet sas : masterSLWT.getSlideAtomsSets()) {
|
||||||
// Notes first
|
Record r = getCoreRecordForSAS(sas);
|
||||||
for (org.apache.poi.hslf.record.Notes n : notesRecords) {
|
int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier();
|
||||||
HSLFNotes hn = null;
|
if (r instanceof Slide) {
|
||||||
if (n != null) {
|
HSLFTitleMaster master = new HSLFTitleMaster((Slide)r, sheetNo);
|
||||||
hn = new HSLFNotes(n);
|
master.setSlideShow(this);
|
||||||
hn.setSlideShow(this);
|
_titleMasters.add(master);
|
||||||
}
|
} else if (r instanceof MainMaster) {
|
||||||
_notes.add(hn);
|
HSLFSlideMaster master = new HSLFSlideMaster((MainMaster)r, sheetNo);
|
||||||
}
|
master.setSlideShow(this);
|
||||||
// Then slides
|
_masters.add(master);
|
||||||
for (int i = 0; i < slidesRecords.length; i++) {
|
}
|
||||||
SlideAtomsSet sas = slidesSets[i];
|
}
|
||||||
int slideIdentifier = sas.getSlidePersistAtom().getSlideIdentifier();
|
}
|
||||||
|
|
||||||
// Do we have a notes for this?
|
private void findNotesSlides(Map<Integer,Integer> slideIdToNotes) {
|
||||||
HSLFNotes notes = null;
|
SlideListWithText notesSLWT = _documentRecord.getNotesSlideListWithText();
|
||||||
// Slide.SlideAtom.notesId references the corresponding notes slide.
|
|
||||||
// 0 if slide has no notes.
|
|
||||||
int noteId = slidesRecords[i].getSlideAtom().getNotesID();
|
|
||||||
if (noteId != 0) {
|
|
||||||
Integer notesPos = slideIdToNotes.get(noteId);
|
|
||||||
if (notesPos != null) {
|
|
||||||
notes = _notes.get(notesPos);
|
|
||||||
} else {
|
|
||||||
logger.log(POILogger.ERROR, "Notes not found for noteId=" + noteId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, build our slide
|
if (notesSLWT == null) {
|
||||||
HSLFSlide hs = new HSLFSlide(slidesRecords[i], notes, sas, slideIdentifier, (i + 1));
|
return;
|
||||||
hs.setSlideShow(this);
|
}
|
||||||
_slides.add(hs);
|
|
||||||
}
|
// Match up the records and the SlideAtomSets
|
||||||
|
int idx = -1;
|
||||||
|
for (SlideAtomsSet notesSet : notesSLWT.getSlideAtomsSets()) {
|
||||||
|
idx++;
|
||||||
|
// Get the right core record
|
||||||
|
Record r = getCoreRecordForSAS(notesSet);
|
||||||
|
SlidePersistAtom spa = notesSet.getSlidePersistAtom();
|
||||||
|
|
||||||
|
String loggerLoc = "A Notes SlideAtomSet at "+idx+" said its record was at refID "+spa.getRefID();
|
||||||
|
|
||||||
|
// we need to add null-records, otherwise the index references to other existing don't work anymore
|
||||||
|
if (r == null) {
|
||||||
|
logger.log(POILogger.WARN, loggerLoc+", but that record didn't exist - record ignored.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure it really is a notes record
|
||||||
|
if (!(r instanceof Notes)) {
|
||||||
|
logger.log(POILogger.ERROR, loggerLoc+", but that was actually a " + r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Notes notesRecord = (Notes) r;
|
||||||
|
|
||||||
|
// Record the match between slide id and these notes
|
||||||
|
int slideId = spa.getSlideIdentifier();
|
||||||
|
slideIdToNotes.put(slideId, idx);
|
||||||
|
|
||||||
|
HSLFNotes hn = new HSLFNotes(notesRecord);
|
||||||
|
hn.setSlideShow(this);
|
||||||
|
_notes.add(hn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void findSlides(Map<Integer,Integer> slideIdToNotes) {
|
||||||
|
SlideListWithText slidesSLWT = _documentRecord.getSlideSlideListWithText();
|
||||||
|
if (slidesSLWT == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match up the records and the SlideAtomSets
|
||||||
|
int idx = -1;
|
||||||
|
for (SlideAtomsSet sas : slidesSLWT.getSlideAtomsSets()) {
|
||||||
|
idx++;
|
||||||
|
// Get the right core record
|
||||||
|
SlidePersistAtom spa = sas.getSlidePersistAtom();
|
||||||
|
Record r = getCoreRecordForSAS(sas);
|
||||||
|
|
||||||
|
// Ensure it really is a slide record
|
||||||
|
if (!(r instanceof Slide)) {
|
||||||
|
logger.log(POILogger.ERROR, "A Slide SlideAtomSet at " + idx
|
||||||
|
+ " said its record was at refID "
|
||||||
|
+ spa.getRefID()
|
||||||
|
+ ", but that was actually a " + r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Slide slide = (Slide)r;
|
||||||
|
|
||||||
|
// Do we have a notes for this?
|
||||||
|
HSLFNotes notes = null;
|
||||||
|
// Slide.SlideAtom.notesId references the corresponding notes slide.
|
||||||
|
// 0 if slide has no notes.
|
||||||
|
int noteId = slide.getSlideAtom().getNotesID();
|
||||||
|
if (noteId != 0) {
|
||||||
|
Integer notesPos = slideIdToNotes.get(noteId);
|
||||||
|
if (notesPos != null && 0 <= notesPos && notesPos < _notes.size()) {
|
||||||
|
notes = _notes.get(notesPos);
|
||||||
|
} else {
|
||||||
|
logger.log(POILogger.ERROR, "Notes not found for noteId=" + noteId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, build our slide
|
||||||
|
int slideIdentifier = spa.getSlideIdentifier();
|
||||||
|
HSLFSlide hs = new HSLFSlide(slide, notes, sas, slideIdentifier, (idx + 1));
|
||||||
|
hs.setSlideShow(this);
|
||||||
|
_slides.add(hs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -512,12 +504,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ===============================================================
|
|
||||||
* Accessor Code
|
|
||||||
* ===============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an array of the most recent version of all the interesting
|
* Returns an array of the most recent version of all the interesting
|
||||||
* records
|
* records
|
||||||
@ -604,12 +590,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
return _documentRecord;
|
return _documentRecord;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ===============================================================
|
|
||||||
* Re-ordering Code
|
|
||||||
* ===============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-orders a slide, to a new position.
|
* Re-orders a slide, to a new position.
|
||||||
*
|
*
|
||||||
@ -720,12 +700,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
return removedSlide;
|
return removedSlide;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ===============================================================
|
|
||||||
* Addition Code
|
|
||||||
* ===============================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a blank <code>Slide</code>.
|
* Create a blank <code>Slide</code>.
|
||||||
*
|
*
|
||||||
@ -786,7 +760,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
+ " and identifier " + sp.getSlideIdentifier());
|
+ " and identifier " + sp.getSlideIdentifier());
|
||||||
|
|
||||||
// Add the core records for this new Slide to the record tree
|
// Add the core records for this new Slide to the record tree
|
||||||
org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
|
Slide slideRecord = slide.getSlideRecord();
|
||||||
int psrId = addPersistentObject(slideRecord);
|
int psrId = addPersistentObject(slideRecord);
|
||||||
sp.setRefID(psrId);
|
sp.setRefID(psrId);
|
||||||
slideRecord.setSheetId(psrId);
|
slideRecord.setSheetId(psrId);
|
||||||
@ -1049,7 +1023,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap
|
|||||||
} else {
|
} else {
|
||||||
ctrl.setLinkURL(link.getAddress());
|
ctrl.setLinkURL(link.getAddress());
|
||||||
}
|
}
|
||||||
ctrl.setLinkTitle(link.getTitle());
|
ctrl.setLinkTitle(link.getLabel());
|
||||||
|
|
||||||
int objectId = addToObjListAtom(ctrl);
|
int objectId = addToObjListAtom(ctrl);
|
||||||
link.setId(objectId);
|
link.setId(objectId);
|
||||||
|
@ -103,6 +103,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
|
|
||||||
private boolean _dirty = false;
|
private boolean _dirty = false;
|
||||||
|
|
||||||
|
private final List<HSLFTextParagraph> parentList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Text Run from a Unicode text block.
|
* Constructs a Text Run from a Unicode text block.
|
||||||
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
|
* Either a {@link TextCharsAtom} or a {@link TextBytesAtom} needs to be provided.
|
||||||
@ -110,11 +112,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
* @param tha the TextHeaderAtom that defines what's what
|
* @param tha the TextHeaderAtom that defines what's what
|
||||||
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
|
* @param tba the TextBytesAtom containing the text or null if {@link TextCharsAtom} is provided
|
||||||
* @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided
|
* @param tca the TextCharsAtom containing the text or null if {@link TextBytesAtom} is provided
|
||||||
|
* @param parentList the list which contains this paragraph
|
||||||
*/
|
*/
|
||||||
/* package */ HSLFTextParagraph(
|
/* package */ HSLFTextParagraph(
|
||||||
TextHeaderAtom tha,
|
TextHeaderAtom tha,
|
||||||
TextBytesAtom tba,
|
TextBytesAtom tba,
|
||||||
TextCharsAtom tca
|
TextCharsAtom tca,
|
||||||
|
List<HSLFTextParagraph> parentList
|
||||||
) {
|
) {
|
||||||
if (tha == null) {
|
if (tha == null) {
|
||||||
throw new IllegalArgumentException("TextHeaderAtom must be set.");
|
throw new IllegalArgumentException("TextHeaderAtom must be set.");
|
||||||
@ -122,6 +126,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
_headerAtom = tha;
|
_headerAtom = tha;
|
||||||
_byteAtom = tba;
|
_byteAtom = tba;
|
||||||
_charAtom = tca;
|
_charAtom = tca;
|
||||||
|
this.parentList = parentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */HSLFTextParagraph(HSLFTextParagraph other) {
|
/* package */HSLFTextParagraph(HSLFTextParagraph other) {
|
||||||
@ -133,6 +138,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
_ruler = other._ruler;
|
_ruler = other._ruler;
|
||||||
shapeId = other.shapeId;
|
shapeId = other.shapeId;
|
||||||
_paragraphStyle.copy(other._paragraphStyle);
|
_paragraphStyle.copy(other._paragraphStyle);
|
||||||
|
parentList = other.parentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addTextRun(HSLFTextRun run) {
|
public void addTextRun(HSLFTextRun run) {
|
||||||
@ -168,7 +174,23 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
||||||
* Also passes it on to our child RichTextRuns
|
* Also passes it on to our child RichTextRuns
|
||||||
*/
|
*/
|
||||||
public void supplySheet(HSLFSheet sheet) {
|
public static void supplySheet(List<HSLFTextParagraph> paragraphs, HSLFSheet sheet) {
|
||||||
|
if (paragraphs == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (HSLFTextParagraph p : paragraphs) {
|
||||||
|
p.supplySheet(sheet);
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sheet.getSlideShow() != null);
|
||||||
|
applyHyperlinks(paragraphs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supply the Sheet we belong to, which might have an assigned SlideShow
|
||||||
|
* Also passes it on to our child RichTextRuns
|
||||||
|
*/
|
||||||
|
private void supplySheet(HSLFSheet sheet) {
|
||||||
this._sheet = sheet;
|
this._sheet = sheet;
|
||||||
|
|
||||||
if (_runs == null) return;
|
if (_runs == null) return;
|
||||||
@ -942,7 +964,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
if (addParagraph && !lastParaEmpty) {
|
if (addParagraph && !lastParaEmpty) {
|
||||||
TextPropCollection tpc = htp.getParagraphStyle();
|
TextPropCollection tpc = htp.getParagraphStyle();
|
||||||
HSLFTextParagraph prevHtp = htp;
|
HSLFTextParagraph prevHtp = htp;
|
||||||
htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom);
|
htp = new HSLFTextParagraph(htp._headerAtom, htp._byteAtom, htp._charAtom, paragraphs);
|
||||||
htp.getParagraphStyle().copy(tpc);
|
htp.getParagraphStyle().copy(tpc);
|
||||||
htp.setParentShape(prevHtp.getParentShape());
|
htp.setParentShape(prevHtp.getParentShape());
|
||||||
htp.setShapeId(prevHtp.getShapeId());
|
htp.setShapeId(prevHtp.getShapeId());
|
||||||
@ -1211,7 +1233,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
|
|
||||||
// split, but keep delimiter
|
// split, but keep delimiter
|
||||||
for (String para : rawText.split("(?<=\r)")) {
|
for (String para : rawText.split("(?<=\r)")) {
|
||||||
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);
|
HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, paragraphs);
|
||||||
paragraphs.add(tpara);
|
paragraphs.add(tpara);
|
||||||
tpara._ruler = ruler;
|
tpara._ruler = ruler;
|
||||||
tpara.getParagraphStyle().updateTextSize(para.length());
|
tpara.getParagraphStyle().updateTextSize(para.length());
|
||||||
@ -1235,6 +1257,22 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
return paragraphCollection;
|
return paragraphCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected static void applyHyperlinks(List<HSLFTextParagraph> paragraphs) {
|
||||||
|
List<HSLFHyperlink> links = HSLFHyperlink.find(paragraphs);
|
||||||
|
|
||||||
|
for (HSLFHyperlink h : links) {
|
||||||
|
int csIdx = 0;
|
||||||
|
for (HSLFTextParagraph p : paragraphs) {
|
||||||
|
for (HSLFTextRun r : p) {
|
||||||
|
if (h.getStartIndex() <= csIdx && csIdx < h.getEndIndex()) {
|
||||||
|
r.setHyperlinkId(h.getId());
|
||||||
|
}
|
||||||
|
csIdx += r.getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected static void applyCharacterStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> charStyles) {
|
protected static void applyCharacterStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> charStyles) {
|
||||||
int paraIdx = 0, runIdx = 0;
|
int paraIdx = 0, runIdx = 0;
|
||||||
HSLFTextRun trun;
|
HSLFTextRun trun;
|
||||||
@ -1340,15 +1378,17 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
|
TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
|
||||||
wrapper.appendChildRecord(sta);
|
wrapper.appendChildRecord(sta);
|
||||||
|
|
||||||
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null);
|
List<HSLFTextParagraph> paragraphs = new ArrayList<HSLFTextParagraph>(1);
|
||||||
|
HSLFTextParagraph htp = new HSLFTextParagraph(tha, tba, null, paragraphs);
|
||||||
htp.setParagraphStyle(paraStyle);
|
htp.setParagraphStyle(paraStyle);
|
||||||
|
paragraphs.add(htp);
|
||||||
|
|
||||||
HSLFTextRun htr = new HSLFTextRun(htp);
|
HSLFTextRun htr = new HSLFTextRun(htp);
|
||||||
htr.setCharacterStyle(charStyle);
|
htr.setCharacterStyle(charStyle);
|
||||||
htr.setText("");
|
htr.setText("");
|
||||||
htp.addTextRun(htr);
|
htp.addTextRun(htr);
|
||||||
|
|
||||||
return Arrays.asList(htp);
|
return paragraphs;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EscherTextboxWrapper getTextboxWrapper() {
|
public EscherTextboxWrapper getTextboxWrapper() {
|
||||||
@ -1397,4 +1437,23 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText
|
|||||||
public boolean isDirty() {
|
public boolean isDirty() {
|
||||||
return _dirty;
|
return _dirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the start index of the given text run
|
||||||
|
*
|
||||||
|
* @param textrun the text run to search for
|
||||||
|
* @return the start index with the paragraph collection or -1 if not found
|
||||||
|
*/
|
||||||
|
/* package */ int getStartIdxOfTextRun(HSLFTextRun textrun) {
|
||||||
|
int idx = 0;
|
||||||
|
for (HSLFTextParagraph p : parentList) {
|
||||||
|
for (HSLFTextRun r : p) {
|
||||||
|
if (r == textrun) {
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
idx += r.getLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
@ -27,6 +27,10 @@ import org.apache.poi.hslf.model.textproperties.CharFlagsTextProp;
|
|||||||
import org.apache.poi.hslf.model.textproperties.TextProp;
|
import org.apache.poi.hslf.model.textproperties.TextProp;
|
||||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
|
||||||
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
|
import org.apache.poi.hslf.model.textproperties.TextPropCollection.TextPropType;
|
||||||
|
import org.apache.poi.hslf.record.ExHyperlink;
|
||||||
|
import org.apache.poi.hslf.record.InteractiveInfo;
|
||||||
|
import org.apache.poi.hslf.record.InteractiveInfoAtom;
|
||||||
|
import org.apache.poi.hslf.record.Record;
|
||||||
import org.apache.poi.sl.draw.DrawPaint;
|
import org.apache.poi.sl.draw.DrawPaint;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
|
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
|
||||||
@ -47,6 +51,7 @@ public final class HSLFTextRun implements TextRun {
|
|||||||
private HSLFTextParagraph parentParagraph;
|
private HSLFTextParagraph parentParagraph;
|
||||||
private String _runText = "";
|
private String _runText = "";
|
||||||
private String _fontFamily;
|
private String _fontFamily;
|
||||||
|
private int hyperlinkId = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our paragraph and character style.
|
* Our paragraph and character style.
|
||||||
@ -390,4 +395,64 @@ public final class HSLFTextRun implements TextRun {
|
|||||||
public byte getPitchAndFamily() {
|
public byte getPitchAndFamily() {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the associated hyperlink id - currently this is only used while parsing and
|
||||||
|
* can't be used for update a ppt
|
||||||
|
*
|
||||||
|
* @param hyperlink the id or -1 to unset it
|
||||||
|
*/
|
||||||
|
public void setHyperlinkId(int hyperlinkId) {
|
||||||
|
this.hyperlinkId = hyperlinkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the associated hyperlink id
|
||||||
|
*
|
||||||
|
* @return the hyperlink id
|
||||||
|
*/
|
||||||
|
public int getHyperlinkId() {
|
||||||
|
return hyperlinkId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HSLFHyperlink getHyperlink() {
|
||||||
|
if (hyperlinkId == -1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExHyperlink linkRecord = parentParagraph.getSheet().getSlideShow().getDocumentRecord().getExObjList().get(hyperlinkId);
|
||||||
|
if (linkRecord == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveInfoAtom info = null;
|
||||||
|
for (Record r : parentParagraph.getRecords()) {
|
||||||
|
if (r instanceof InteractiveInfo) {
|
||||||
|
InteractiveInfo ii = (InteractiveInfo)r;
|
||||||
|
InteractiveInfoAtom iia = ii.getInteractiveInfoAtom();
|
||||||
|
if (iia.getHyperlinkID() == hyperlinkId) {
|
||||||
|
info = iia;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (info == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check previous/next sibling runs for same hyperlink id and return the whole string length
|
||||||
|
int startIdx = parentParagraph.getStartIdxOfTextRun(this);
|
||||||
|
|
||||||
|
HSLFHyperlink link = new HSLFHyperlink();
|
||||||
|
link.setId(hyperlinkId);
|
||||||
|
link.setType(info.getAction());
|
||||||
|
link.setLabel(linkRecord.getLinkTitle());
|
||||||
|
link.setAddress(linkRecord.getLinkURL());
|
||||||
|
link.setStartIndex(startIdx);
|
||||||
|
link.setEndIndex(startIdx+getLength());
|
||||||
|
|
||||||
|
return link;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -594,13 +594,8 @@ implements TextShape<HSLFShape,HSLFTextParagraph> {
|
|||||||
// (We can't do it in the constructor because the sheet
|
// (We can't do it in the constructor because the sheet
|
||||||
// is not assigned then, it's only built once we have
|
// is not assigned then, it's only built once we have
|
||||||
// all the records)
|
// all the records)
|
||||||
List<HSLFTextParagraph> paras = getTextParagraphs();
|
List<HSLFTextParagraph> ltp = getTextParagraphs();
|
||||||
if (paras != null) {
|
HSLFTextParagraph.supplySheet(ltp, sheet);
|
||||||
for (HSLFTextParagraph htp : paras) {
|
|
||||||
// Supply the sheet to our child RichTextRuns
|
|
||||||
htp.supplySheet(_sheet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,11 +57,11 @@ public final class TestHyperlink {
|
|||||||
assertNotNull(links);
|
assertNotNull(links);
|
||||||
assertEquals(2, links.size());
|
assertEquals(2, links.size());
|
||||||
|
|
||||||
assertEquals("http://jakarta.apache.org/poi/", links.get(0).getTitle());
|
assertEquals("http://jakarta.apache.org/poi/", links.get(0).getLabel());
|
||||||
assertEquals("http://jakarta.apache.org/poi/", links.get(0).getAddress());
|
assertEquals("http://jakarta.apache.org/poi/", links.get(0).getAddress());
|
||||||
assertEquals("http://jakarta.apache.org/poi/", rawText.substring(links.get(0).getStartIndex(), links.get(0).getEndIndex()-1));
|
assertEquals("http://jakarta.apache.org/poi/", rawText.substring(links.get(0).getStartIndex(), links.get(0).getEndIndex()-1));
|
||||||
|
|
||||||
assertEquals("http://slashdot.org/", links.get(1).getTitle());
|
assertEquals("http://slashdot.org/", links.get(1).getLabel());
|
||||||
assertEquals("http://slashdot.org/", links.get(1).getAddress());
|
assertEquals("http://slashdot.org/", links.get(1).getAddress());
|
||||||
assertEquals("http://slashdot.org/", rawText.substring(links.get(1).getStartIndex(), links.get(1).getEndIndex()-1));
|
assertEquals("http://slashdot.org/", rawText.substring(links.get(1).getStartIndex(), links.get(1).getEndIndex()-1));
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ public final class TestHyperlink {
|
|||||||
assertNotNull(links);
|
assertNotNull(links);
|
||||||
assertEquals(1, links.size());
|
assertEquals(1, links.size());
|
||||||
|
|
||||||
assertEquals("http://jakarta.apache.org/poi/hssf/", links.get(0).getTitle());
|
assertEquals("Open Jakarta POI HSSF module test ", links.get(0).getLabel());
|
||||||
assertEquals("http://jakarta.apache.org/poi/hssf/", links.get(0).getAddress());
|
assertEquals("http://jakarta.apache.org/poi/hssf/", links.get(0).getAddress());
|
||||||
assertEquals("Jakarta HSSF", rawText.substring(links.get(0).getStartIndex(), links.get(0).getEndIndex()-1));
|
assertEquals("Jakarta HSSF", rawText.substring(links.get(0).getStartIndex(), links.get(0).getEndIndex()-1));
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,10 @@ import static org.junit.Assert.assertTrue;
|
|||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.text.AttributedCharacterIterator;
|
||||||
|
import java.text.AttributedCharacterIterator.Attribute;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -47,7 +51,9 @@ import org.apache.poi.hslf.record.Record;
|
|||||||
import org.apache.poi.hslf.record.SlideListWithText;
|
import org.apache.poi.hslf.record.SlideListWithText;
|
||||||
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
|
||||||
import org.apache.poi.hslf.record.TextHeaderAtom;
|
import org.apache.poi.hslf.record.TextHeaderAtom;
|
||||||
|
import org.apache.poi.hssf.usermodel.DummyGraphics2d;
|
||||||
import org.apache.poi.sl.draw.DrawPaint;
|
import org.apache.poi.sl.draw.DrawPaint;
|
||||||
|
import org.apache.poi.sl.draw.DrawTextParagraph;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle;
|
import org.apache.poi.sl.usermodel.PaintStyle;
|
||||||
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
|
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;
|
||||||
import org.apache.poi.sl.usermodel.PictureData.PictureType;
|
import org.apache.poi.sl.usermodel.PictureData.PictureType;
|
||||||
@ -67,8 +73,6 @@ import org.junit.Test;
|
|||||||
/**
|
/**
|
||||||
* Testcases for bugs entered in bugzilla
|
* Testcases for bugs entered in bugzilla
|
||||||
* the Test name contains the bugzilla bug id
|
* the Test name contains the bugzilla bug id
|
||||||
*
|
|
||||||
* @author Yegor Kozlov
|
|
||||||
*/
|
*/
|
||||||
public final class TestBugs {
|
public final class TestBugs {
|
||||||
/**
|
/**
|
||||||
@ -823,6 +827,59 @@ public final class TestBugs {
|
|||||||
ppt.close();
|
ppt.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void bug57796() throws IOException {
|
||||||
|
HSLFSlideShow ppt = open("WithLinks.ppt");
|
||||||
|
HSLFSlide slide = ppt.getSlides().get(0);
|
||||||
|
HSLFTextShape shape = (HSLFTextShape)slide.getShapes().get(1);
|
||||||
|
List<HSLFHyperlink> hlList = HSLFHyperlink.find(shape);
|
||||||
|
HSLFHyperlink hlShape = hlList.get(0);
|
||||||
|
HSLFTextRun r = shape.getTextParagraphs().get(1).getTextRuns().get(0);
|
||||||
|
HSLFHyperlink hlRun = r.getHyperlink();
|
||||||
|
assertEquals(hlRun.getId(), hlShape.getId());
|
||||||
|
assertEquals(hlRun.getAddress(), hlShape.getAddress());
|
||||||
|
assertEquals(hlRun.getLabel(), hlShape.getLabel());
|
||||||
|
assertEquals(hlRun.getType(), hlShape.getType());
|
||||||
|
assertEquals(hlRun.getStartIndex(), hlShape.getStartIndex());
|
||||||
|
assertEquals(hlRun.getEndIndex(), hlShape.getEndIndex());
|
||||||
|
|
||||||
|
OutputStream nullOutput = new OutputStream(){
|
||||||
|
public void write(int b) throws IOException {}
|
||||||
|
};
|
||||||
|
|
||||||
|
final boolean found[] = { false };
|
||||||
|
DummyGraphics2d dgfx = new DummyGraphics2d(new PrintStream(nullOutput)){
|
||||||
|
public void drawString(AttributedCharacterIterator iterator, float x, float y) {
|
||||||
|
// For the test file, common sl draws textruns one by one and not mixed
|
||||||
|
// so we evaluate the whole iterator
|
||||||
|
Map<Attribute, Object> attributes = null;
|
||||||
|
StringBuffer sb = new StringBuffer();
|
||||||
|
|
||||||
|
for (char c = iterator.first();
|
||||||
|
c != AttributedCharacterIterator.DONE;
|
||||||
|
c = iterator.next()) {
|
||||||
|
sb.append(c);
|
||||||
|
attributes = iterator.getAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ("Jakarta HSSF".equals(sb.toString())) {
|
||||||
|
// this is a test for a manually modified ppt, for real hyperlink label
|
||||||
|
// one would need to access the screen tip record
|
||||||
|
String href = (String)attributes.get(DrawTextParagraph.HYPERLINK_HREF);
|
||||||
|
String label = (String)attributes.get(DrawTextParagraph.HYPERLINK_LABEL);
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/hssf/", href);
|
||||||
|
assertEquals("Open Jakarta POI HSSF module test ", label);
|
||||||
|
found[0] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ppt.getSlides().get(1).draw(dgfx);
|
||||||
|
assertTrue(found[0]);
|
||||||
|
|
||||||
|
ppt.close();
|
||||||
|
}
|
||||||
|
|
||||||
private static HSLFSlideShow open(String fileName) throws IOException {
|
private static HSLFSlideShow open(String fileName) throws IOException {
|
||||||
File sample = HSLFTestDataSamples.getSampleFile(fileName);
|
File sample = HSLFTestDataSamples.getSampleFile(fileName);
|
||||||
return (HSLFSlideShow)SlideShowFactory.create(sample);
|
return (HSLFSlideShow)SlideShowFactory.create(sample);
|
||||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user