diff options
author | Andreas Beeker <kiwiwings@apache.org> | 2016-01-12 23:20:48 +0000 |
---|---|---|
committer | Andreas Beeker <kiwiwings@apache.org> | 2016-01-12 23:20:48 +0000 |
commit | 05cec9b2513389554ce3562e6b4043710d38a317 (patch) | |
tree | 3c8849dd2cecc03c0aa567f606376b7475ccd643 | |
parent | f069c83071efafc6db2cefbdad4ab85677d81db5 (diff) | |
download | poi-05cec9b2513389554ce3562e6b4043710d38a317.tar.gz poi-05cec9b2513389554ce3562e6b4043710d38a317.zip |
#57796 - Support hyperlink extraction when rendering slides
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724338 13f79535-47bb-0310-9956-ffa450edef68
20 files changed, 456 insertions, 247 deletions
diff --git a/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java b/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java index 1d8c95a19f..44e5d81c1c 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java +++ b/src/examples/src/org/apache/poi/hslf/examples/CreateHyperlink.java @@ -46,7 +46,7 @@ public abstract class CreateHyperlink { String text = textBox1.getText(); HSLFHyperlink link = new HSLFHyperlink(); link.setAddress("http://www.apache.org"); - link.setTitle(textBox1.getText()); + link.setLabel(textBox1.getText()); int linkId = ppt.addHyperlink(link); // apply link to the text diff --git a/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java b/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java index c054d2e7ac..8cbbcdc852 100644 --- a/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java +++ b/src/examples/src/org/apache/poi/hslf/examples/Hyperlinks.java @@ -70,6 +70,6 @@ public final class Hyperlinks { //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 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); } } diff --git a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java index 65233fe0ba..e8a7b0b216 100644 --- a/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java +++ b/src/java/org/apache/poi/sl/draw/DrawTextParagraph.java @@ -24,6 +24,7 @@ import java.awt.font.LineBreakMeasurer; import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.awt.geom.Rectangle2D;
+import java.io.InvalidObjectException;
import java.text.AttributedCharacterIterator;
import java.text.AttributedCharacterIterator.Attribute;
import java.text.AttributedString;
@@ -32,6 +33,7 @@ import java.util.List; import java.util.Map;
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.PaintStyle;
import org.apache.poi.sl.usermodel.PlaceableShape;
@@ -46,6 +48,10 @@ import org.apache.poi.util.StringUtil; import org.apache.poi.util.Units;
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;
double x, y;
protected List<DrawTextFragment> lines = new ArrayList<DrawTextFragment>();
@@ -58,6 +64,31 @@ public class DrawTextParagraph implements Drawable { */
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) {
this.paragraph = paragraph;
}
@@ -79,10 +110,10 @@ public class DrawTextParagraph implements Drawable { public void setAutoNumberingIdx(int index) {
autoNbrIdx = index;
}
-
+
public void draw(Graphics2D graphics){
if (lines.isEmpty()) return;
-
+
double penY = y;
boolean firstLine = true;
@@ -100,7 +131,7 @@ public class DrawTextParagraph implements Drawable { // special handling for HSLF
indent -= leftMargin;
}
-
+
// Double rightMargin = paragraph.getRightMargin();
// if (rightMargin == null) {
// rightMargin = 0d;
@@ -109,7 +140,7 @@ public class DrawTextParagraph implements Drawable { //The vertical line spacing
Double spacing = paragraph.getLineSpacing();
if (spacing == null) spacing = 100d;
-
+
for(DrawTextFragment line : lines){
double penX;
@@ -118,7 +149,7 @@ public class DrawTextParagraph implements Drawable { // TODO: find out character style for empty, but bulleted/numbered lines
bullet = getBullet(graphics, line.getAttributedString().getIterator());
}
-
+
if (bullet != null){
bullet.setPosition(x+leftMargin+indent, penY);
bullet.draw(graphics);
@@ -168,7 +199,7 @@ public class DrawTextParagraph implements Drawable { y = penY - y;
}
-
+
public float getFirstLineHeight() {
return (lines.isEmpty()) ? 0 : lines.get(0).getHeight();
}
@@ -180,7 +211,7 @@ public class DrawTextParagraph implements Drawable { public boolean isEmptyParagraph() {
return (lines.isEmpty() || rawText.trim().isEmpty());
}
-
+
public void applyTransform(Graphics2D graphics) {
}
@@ -265,7 +296,7 @@ public class DrawTextParagraph implements Drawable { String buFont = bulletStyle.getBulletFont();
if (buFont == null) buFont = paragraph.getDefaultFontFamily();
assert(buFont != null);
-
+
PlaceableShape<?,?> ps = getParagraphShape();
PaintStyle fgPaintStyle = bulletStyle.getBulletFontColor();
Paint fgPaint;
@@ -277,11 +308,11 @@ public class DrawTextParagraph implements Drawable { float fontSize = (Float)firstLineAttr.getAttribute(TextAttribute.SIZE);
Double buSz = bulletStyle.getBulletFontSize();
- if (buSz == null) buSz = 100d;
+ if (buSz == null) buSz = 100d;
if (buSz > 0) fontSize *= buSz* 0.01;
else fontSize = (float)-buSz;
-
+
AttributedString str = new AttributedString(mapFontCharset(buCharacter,buFont));
str.addAttribute(TextAttribute.FOREGROUND, fgPaint);
str.addAttribute(TextAttribute.FAMILY, buFont);
@@ -313,7 +344,7 @@ public class DrawTextParagraph implements Drawable { case SMALL: c = Character.toLowerCase(c); break;
case NONE: break;
}
-
+
buf.append(c);
break;
}
@@ -321,7 +352,7 @@ public class DrawTextParagraph implements Drawable { return buf.toString();
}
-
+
/**
* Replace a tab with the effective number of white spaces.
*/
@@ -334,7 +365,7 @@ public class DrawTextParagraph implements Drawable { Double fs = tr.getFontSize();
if (fs == null) fs = 12d;
string.addAttribute(TextAttribute.SIZE, fs.floatValue());
-
+
TextLayout l = new TextLayout(string.getIterator(), new FontRenderContext(null, true, true));
double wspace = l.getAdvance();
@@ -348,7 +379,7 @@ public class DrawTextParagraph implements Drawable { }
return buf.toString();
}
-
+
/**
* Returns wrapping width to break lines in this paragraph
@@ -418,7 +449,7 @@ public class DrawTextParagraph implements Drawable { this.endIndex = endIndex;
}
}
-
+
/**
* Helper method for paint style relative to bounds, e.g. gradient paint
*/
@@ -443,7 +474,7 @@ public class DrawTextParagraph implements Drawable { if (text == null) text = new StringBuilder();
PlaceableShape<?,?> ps = getParagraphShape();
-
+
DrawFontManager fontHandler = (DrawFontManager)graphics.getRenderingHint(Drawable.FONT_HANDLER);
for (TextRun run : paragraph){
@@ -464,7 +495,7 @@ public class DrawTextParagraph implements Drawable { if (fontFamily == null) {
fontFamily = paragraph.getDefaultFontFamily();
}
-
+
int beginIndex = text.length();
text.append(mapFontCharset(runText,fontFamily));
int endIndex = text.length();
@@ -498,6 +529,12 @@ public class DrawTextParagraph implements Drawable { if(run.isSuperscript()) {
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
@@ -517,9 +554,9 @@ public class DrawTextParagraph implements Drawable { }
protected boolean isHSLF() {
- return paragraph.getClass().getName().contains("HSLF");
+ return paragraph.getClass().getName().contains("HSLF");
}
-
+
/**
* Map text charset depending on font family.
* Currently this only maps for wingdings font (into unicode private use area)
@@ -527,7 +564,7 @@ public class DrawTextParagraph implements Drawable { * @param text the raw text
* @param fontFamily the font family
* @return AttributedString with mapped codepoints
- *
+ *
* @see <a href="http://stackoverflow.com/questions/8692095">Drawing exotic fonts in a java applet</a>
* @see StringUtil#mapMsCodepointString(String)
*/
diff --git a/src/java/org/apache/poi/sl/usermodel/TextRun.java b/src/java/org/apache/poi/sl/usermodel/TextRun.java index 9eb27b616e..28db797958 100644 --- a/src/java/org/apache/poi/sl/usermodel/TextRun.java +++ b/src/java/org/apache/poi/sl/usermodel/TextRun.java @@ -156,4 +156,11 @@ public interface TextRun { * @return the pitch and family id or -1 if not applicable */ byte getPitchAndFamily(); + + /** + * Return the associated hyperlink + * + * @return the associated hyperlink or null if no hyperlink was set + */ + Hyperlink getHyperlink(); } diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java index 5a25851b5c..0b093ecacb 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFHyperlink.java @@ -18,15 +18,13 @@ package org.apache.poi.xslf.usermodel; import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.openxml4j.opc.TargetMode;
+import org.apache.poi.sl.usermodel.Hyperlink;
import org.apache.poi.util.Internal;
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;
import java.net.URI;
-/**
- * @author Yegor Kozlov
- */
-public class XSLFHyperlink {
+public class XSLFHyperlink implements Hyperlink {
final XSLFTextRun _r;
final CTHyperlink _link;
@@ -40,15 +38,39 @@ public class XSLFHyperlink { return _link;
}
+ @Override
public void setAddress(String address){
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
PackageRelationship rel =
sheet.getPackagePart().
addExternalRelationship(address, XSLFRelation.HYPERLINK.getRelation());
_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){
XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();
PackageRelationship rel =
diff --git a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java index 8ce7c5241e..1b2272ba3e 100644 --- a/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java +++ b/src/ooxml/java/org/apache/poi/xslf/usermodel/XSLFTextRun.java @@ -449,6 +449,7 @@ public class XSLFTextRun implements TextRun { return link;
}
+ @Override
public XSLFHyperlink getHyperlink(){
if(!_r.getRPr().isSetHlinkClick()) return null;
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java index 0022822b82..4a3af15f8d 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/PPGraphics2D.java @@ -282,7 +282,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { */ public void drawString(String s, float x, float y) { HSLFTextBox txt = new HSLFTextBox(_group); - txt.getTextParagraphs().get(0).supplySheet(_group.getSheet()); + txt.setSheet(_group.getSheet()); txt.setText(s); HSLFTextRun rt = txt.getTextParagraphs().get(0).getTextRuns().get(0); diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java index d20f0efa9b..f896103b04 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFHyperlink.java @@ -29,13 +29,12 @@ 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.hslf.record.TxInteractiveInfoAtom; +import org.apache.poi.sl.usermodel.Hyperlink; /** * 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_PREVIOUSSLIDE = InteractiveInfoAtom.LINK_PreviousSlide; public static final byte LINK_FIRSTSLIDE = InteractiveInfoAtom.LINK_FirstSlide; @@ -47,7 +46,7 @@ public final class HSLFHyperlink { private int id=-1; private int type; private String address; - private String title; + private String label; private int startIndex, endIndex; /** @@ -57,6 +56,7 @@ public final class HSLFHyperlink { * @return the hyperlink URL * @see InteractiveInfoAtom */ + @Override public int getType() { return type; } @@ -65,35 +65,31 @@ public final class HSLFHyperlink { type = val; switch(type){ case LINK_NEXTSLIDE: - title = "NEXT"; + label = "NEXT"; address = "1,-1,NEXT"; break; case LINK_PREVIOUSSLIDE: - title = "PREV"; + label = "PREV"; address = "1,-1,PREV"; break; case LINK_FIRSTSLIDE: - title = "FIRST"; + label = "FIRST"; address = "1,-1,FIRST"; break; case LINK_LASTSLIDE: - title = "LAST"; + label = "LAST"; address = "1,-1,LAST"; break; case LINK_SLIDENUMBER: break; default: - title = ""; + label = ""; address = ""; break; } } - /** - * Gets the hyperlink URL - * - * @return the hyperlink URL - */ + @Override public String getAddress() { return address; } @@ -101,10 +97,11 @@ public final class HSLFHyperlink { public void setAddress(HSLFSlide slide) { String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber(); setAddress(href);; - setTitle("Slide " + slide.getSlideNumber()); + setLabel("Slide " + slide.getSlideNumber()); setType(HSLFHyperlink.LINK_SLIDENUMBER); } + @Override public void setAddress(String str) { address = str; } @@ -117,17 +114,14 @@ public final class HSLFHyperlink { this.id = id; } - /** - * Gets the hyperlink user-friendly title (if different from URL) - * - * @return the hyperlink user-friendly title - */ - public String getTitle() { - return title; + @Override + public String getLabel() { + return label; } - public void setTitle(String str) { - title = str; + @Override + public void setLabel(String str) { + label = str; } /** @@ -140,6 +134,15 @@ public final class HSLFHyperlink { } /** + * Sets the beginning character position + * + * @param startIndex the beginning character position + */ + public void setStartIndex(int startIndex) { + this.startIndex = startIndex; + } + + /** * Gets the ending character position * * @return the ending character position @@ -149,6 +152,15 @@ public final class HSLFHyperlink { } /** + * 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 * * @param shape <code>TextRun</code> to lookup hyperlinks in @@ -222,9 +234,10 @@ public final class HSLFHyperlink { } HSLFHyperlink link = new HSLFHyperlink(); - link.title = linkRecord.getLinkTitle(); - link.address = linkRecord.getLinkURL(); - link.type = info.getAction(); + link.setId(id); + link.setType(info.getAction()); + link.setLabel(linkRecord.getLinkTitle()); + link.setAddress(linkRecord.getLinkURL()); out.add(link); if (iter.hasNext()) { @@ -234,8 +247,8 @@ public final class HSLFHyperlink { continue; } TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)r; - link.startIndex = txinfo.getStartIndex(); - link.endIndex = txinfo.getEndIndex(); + link.setStartIndex(txinfo.getStartIndex()); + link.setEndIndex(txinfo.getEndIndex()); } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java index 50125ea48e..d64775e117 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFNotes.java @@ -56,13 +56,6 @@ public final class HSLFNotes extends HSLFSheet implements Notes<HSLFShape,HSLFTe if (_paragraphs.isEmpty()) { 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); - } - } } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java index 3fe79aeb16..ee61557734 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSheet.java @@ -133,9 +133,7 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H List<List<HSLFTextParagraph>> trs = getTextParagraphs(); if (trs == null) return; for (List<HSLFTextParagraph> ltp : trs) { - for (HSLFTextParagraph tp : ltp) { - tp.supplySheet(this); - } + HSLFTextParagraph.supplySheet(ltp, this); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java index 4da85a946e..b78a5c8fad 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSimpleShape.java @@ -310,7 +310,7 @@ public abstract class HSLFSimpleShape extends HSLFShape implements SimpleShape<H infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber); break; default: - logger.log(POILogger.WARN, "Ignore unknown hyperlink type : "+link.getTitle()); + logger.log(POILogger.WARN, "Ignore unknown hyperlink type : "+link.getLabel()); break; } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java index 73223646c7..453a790fdd 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlide.java @@ -94,12 +94,6 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) { if (!_paragraphs.contains(l)) _paragraphs.add(l); } - - for(List<HSLFTextParagraph> ltp : _paragraphs) { - for (HSLFTextParagraph tp : ltp) { - tp.supplySheet(this); - } - } } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java index 1e89b69a9e..9b5668ffee 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideMaster.java @@ -51,12 +51,6 @@ public final class HSLFSlideMaster extends HSLFMasterSheet { for (List<HSLFTextParagraph> l : HSLFTextParagraph.findTextParagraphs(getPPDrawing(), this)) { if (!_paragraphs.contains(l)) _paragraphs.add(l); } - - for (List<HSLFTextParagraph> p : _paragraphs) { - for (HSLFTextParagraph htp : p) { - htp.supplySheet(this); - } - } } /** diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java index f08c398074..fae9e20593 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFSlideShow.java @@ -33,6 +33,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.apache.poi.hslf.record.MainMaster; import org.apache.poi.ddf.EscherBSERecord; import org.apache.poi.ddf.EscherContainerRecord; 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.FontEntityAtom; 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.PositionDependentRecord; import org.apache.poi.hslf.record.PositionDependentRecordContainer; 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.Slide; import org.apache.poi.hslf.record.SlideListWithText; import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet; 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()); - /* =============================================================== - * Setup Code - * =============================================================== - */ - - /** * Constructs a Powerpoint document from the underlying * HSLFSlideShow object. Finds the model stuff from this @@ -338,138 +335,133 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap // We always use the latest versions of these records, and use the // SlideAtom/NotesAtom to match them with the StyleAtomSet - SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText(); - 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); - } - } - } - + findMasterSlides(); + // 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 - // notesSLWT - 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); - } + // Start by finding the notes records + findNotesSlides(slideIdToNotes); // Now, do the same thing for our slides - org.apache.poi.hslf.record.Slide[] slidesRecords; - 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) { - slidesRecords[i] = (org.apache.poi.hslf.record.Slide) r; - } else { - logger.log(POILogger.ERROR, "A Slide SlideAtomSet at " + i - + " said its record was at refID " - + slidesSets[i].getSlidePersistAtom().getRefID() - + ", but that was actually a " + r); - } - } - } + findSlides(slideIdToNotes); + } - // Finally, generate model objects for everything - // Notes first - for (org.apache.poi.hslf.record.Notes n : notesRecords) { - HSLFNotes hn = null; - if (n != null) { - hn = new HSLFNotes(n); - hn.setSlideShow(this); - } - _notes.add(hn); - } - // Then slides - for (int i = 0; i < slidesRecords.length; i++) { - SlideAtomsSet sas = slidesSets[i]; - int slideIdentifier = sas.getSlidePersistAtom().getSlideIdentifier(); - - // 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 = 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); - } - } + /** + * 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. + */ + private void findMasterSlides() { + SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText(); + if (masterSLWT == null) { + return; + } + + for (SlideAtomsSet sas : masterSLWT.getSlideAtomsSets()) { + Record r = getCoreRecordForSAS(sas); + int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier(); + if (r instanceof Slide) { + HSLFTitleMaster master = new HSLFTitleMaster((Slide)r, sheetNo); + master.setSlideShow(this); + _titleMasters.add(master); + } else if (r instanceof MainMaster) { + HSLFSlideMaster master = new HSLFSlideMaster((MainMaster)r, sheetNo); + master.setSlideShow(this); + _masters.add(master); + } + } + } + + private void findNotesSlides(Map<Integer,Integer> slideIdToNotes) { + SlideListWithText notesSLWT = _documentRecord.getNotesSlideListWithText(); - // Now, build our slide - HSLFSlide hs = new HSLFSlide(slidesRecords[i], notes, sas, slideIdentifier, (i + 1)); - hs.setSlideShow(this); - _slides.add(hs); - } + if (notesSLWT == null) { + return; + } + + // 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 public void write(OutputStream out) throws IOException { // check for text paragraph modifications @@ -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 * records @@ -604,12 +590,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap return _documentRecord; } - /* - * =============================================================== - * Re-ordering Code - * =============================================================== - */ - /** * Re-orders a slide, to a new position. * @@ -720,12 +700,6 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap return removedSlide; } - /* - * =============================================================== - * Addition Code - * =============================================================== - */ - /** * Create a blank <code>Slide</code>. * @@ -786,7 +760,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap + " and identifier " + sp.getSlideIdentifier()); // 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); sp.setRefID(psrId); slideRecord.setSheetId(psrId); @@ -1049,7 +1023,7 @@ public final class HSLFSlideShow implements SlideShow<HSLFShape,HSLFTextParagrap } else { ctrl.setLinkURL(link.getAddress()); } - ctrl.setLinkTitle(link.getTitle()); + ctrl.setLinkTitle(link.getLabel()); int objectId = addToObjListAtom(ctrl); link.setId(objectId); diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java index f1443ccfe0..ceb4853e30 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextParagraph.java @@ -102,6 +102,8 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText private StyleTextProp9Atom styleTextProp9Atom;
private boolean _dirty = false;
+
+ private final List<HSLFTextParagraph> parentList;
/**
* Constructs a Text Run from a Unicode text block.
@@ -110,11 +112,13 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText * @param tha the TextHeaderAtom that defines what's what
* @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 parentList the list which contains this paragraph
*/
/* package */ HSLFTextParagraph(
TextHeaderAtom tha,
TextBytesAtom tba,
- TextCharsAtom tca
+ TextCharsAtom tca,
+ List<HSLFTextParagraph> parentList
) {
if (tha == null) {
throw new IllegalArgumentException("TextHeaderAtom must be set.");
@@ -122,6 +126,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText _headerAtom = tha;
_byteAtom = tba;
_charAtom = tca;
+ this.parentList = parentList;
}
/* package */HSLFTextParagraph(HSLFTextParagraph other) {
@@ -133,6 +138,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText _ruler = other._ruler;
shapeId = other.shapeId;
_paragraphStyle.copy(other._paragraphStyle);
+ parentList = other.parentList;
}
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
* 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;
if (_runs == null) return;
@@ -942,7 +964,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText if (addParagraph && !lastParaEmpty) {
TextPropCollection tpc = htp.getParagraphStyle();
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.setParentShape(prevHtp.getParentShape());
htp.setShapeId(prevHtp.getShapeId());
@@ -1211,7 +1233,7 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText // split, but keep delimiter
for (String para : rawText.split("(?<=\r)")) {
- HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars);
+ HSLFTextParagraph tpara = new HSLFTextParagraph(header, tbytes, tchars, paragraphs);
paragraphs.add(tpara);
tpara._ruler = ruler;
tpara.getParagraphStyle().updateTextSize(para.length());
@@ -1235,6 +1257,22 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText 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) {
int paraIdx = 0, runIdx = 0;
HSLFTextRun trun;
@@ -1340,15 +1378,17 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText TextPropCollection charStyle = sta.addCharacterTextPropCollection(1);
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);
+ paragraphs.add(htp);
HSLFTextRun htr = new HSLFTextRun(htp);
htr.setCharacterStyle(charStyle);
htr.setText("");
htp.addTextRun(htr);
- return Arrays.asList(htp);
+ return paragraphs;
}
public EscherTextboxWrapper getTextboxWrapper() {
@@ -1397,4 +1437,23 @@ public final class HSLFTextParagraph implements TextParagraph<HSLFShape,HSLFText public boolean isDirty() {
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;
+ }
}
\ No newline at end of file diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java index 437fb745b8..62cd072f21 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextRun.java @@ -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.TextPropCollection; 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.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; @@ -47,6 +51,7 @@ public final class HSLFTextRun implements TextRun { private HSLFTextParagraph parentParagraph; private String _runText = ""; private String _fontFamily; + private int hyperlinkId = -1; /** * Our paragraph and character style. @@ -390,4 +395,64 @@ public final class HSLFTextRun implements TextRun { public byte getPitchAndFamily() { 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; + } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java index 88e5d80016..fbe91040e8 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/HSLFTextShape.java @@ -594,13 +594,8 @@ implements TextShape<HSLFShape,HSLFTextParagraph> { // (We can't do it in the constructor because the sheet // is not assigned then, it's only built once we have // all the records) - List<HSLFTextParagraph> paras = getTextParagraphs(); - if (paras != null) { - for (HSLFTextParagraph htp : paras) { - // Supply the sheet to our child RichTextRuns - htp.supplySheet(_sheet); - } - } + List<HSLFTextParagraph> ltp = getTextParagraphs(); + HSLFTextParagraph.supplySheet(ltp, sheet); } /** diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java index 5429b96fbc..715640a1d5 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/model/TestHyperlink.java @@ -57,11 +57,11 @@ public final class TestHyperlink { assertNotNull(links); 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/", 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/", rawText.substring(links.get(1).getStartIndex(), links.get(1).getEndIndex()-1)); @@ -77,7 +77,7 @@ public final class TestHyperlink { assertNotNull(links); 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("Jakarta HSSF", rawText.substring(links.get(0).getStartIndex(), links.get(0).getEndIndex()-1)); } diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java index 2c166ebf1f..e3b2683e53 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java @@ -26,6 +26,10 @@ import static org.junit.Assert.assertTrue; import java.awt.Color; import java.io.File; 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.Date; 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.SlideAtomsSet; 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.DrawTextParagraph; import org.apache.poi.sl.usermodel.PaintStyle; import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint; import org.apache.poi.sl.usermodel.PictureData.PictureType; @@ -67,8 +73,6 @@ import org.junit.Test; /** * Testcases for bugs entered in bugzilla * the Test name contains the bugzilla bug id - * - * @author Yegor Kozlov */ public final class TestBugs { /** @@ -822,6 +826,59 @@ public final class TestBugs { 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 { File sample = HSLFTestDataSamples.getSampleFile(fileName); diff --git a/test-data/slideshow/WithLinks.ppt b/test-data/slideshow/WithLinks.ppt Binary files differindex f08a81a09b..80d2e6dbb4 100644 --- a/test-data/slideshow/WithLinks.ppt +++ b/test-data/slideshow/WithLinks.ppt |