HSLFSlide slideC = ppt.createSlide();
// link to a URL
- HSLFTextBox textBox1 = new HSLFTextBox();
+ HSLFTextBox textBox1 = slideA.createTextBox();
textBox1.setText("Apache POI");
textBox1.setAnchor(new Rectangle(100, 100, 200, 50));
- String text = textBox1.getText();
- HSLFHyperlink link = new HSLFHyperlink();
- link.setAddress("http://www.apache.org");
- link.setLabel(textBox1.getText());
- int linkId = ppt.addHyperlink(link);
-
- // apply link to the text
- textBox1.setHyperlink(linkId, 0, text.length());
-
- slideA.addShape(textBox1);
+ HSLFHyperlink link1 = textBox1.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+ link1.linkToUrl("http://www.apache.org");
+ link1.setLabel(textBox1.getText());
// link to another slide
- HSLFTextBox textBox2 = new HSLFTextBox();
+ HSLFTextBox textBox2 = slideA.createTextBox();
textBox2.setText("Go to slide #3");
textBox2.setAnchor(new Rectangle(100, 300, 200, 50));
- HSLFHyperlink link2 = new HSLFHyperlink();
- link2.setAddress(slideC);
- ppt.addHyperlink(link2);
-
- // apply link to the whole shape
- textBox2.setHyperlink(link2);
-
- slideA.addShape(textBox2);
+ HSLFHyperlink link2 = textBox2.getTextParagraphs().get(0).getTextRuns().get(0).createHyperlink();
+ link2.linkToSlide(slideC);
FileOutputStream out = new FileOutputStream("hyperlink.ppt");
ppt.write(out);
out.close();
+ ppt.close();
}
}
import java.io.FileInputStream;
import java.util.List;
+import java.util.Locale;
import org.apache.poi.hslf.usermodel.HSLFHyperlink;
import org.apache.poi.hslf.usermodel.HSLFShape;
+import org.apache.poi.hslf.usermodel.HSLFSimpleShape;
import org.apache.poi.hslf.usermodel.HSLFSlide;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
/**
* Demonstrates how to read hyperlinks from a presentation
// read hyperlinks from the slide's text runs
System.out.println("- reading hyperlinks from the text runs");
- for (List<HSLFTextParagraph> txtParas : slide.getTextParagraphs()) {
- List<HSLFHyperlink> links = HSLFHyperlink.find(txtParas);
- String text = HSLFTextParagraph.getRawText(txtParas);
-
- for (HSLFHyperlink link : links) {
- System.out.println(toStr(link, text));
+ for (List<HSLFTextParagraph> paras : slide.getTextParagraphs()) {
+ for (HSLFTextParagraph para : paras) {
+ for (HSLFTextRun run : para) {
+ HSLFHyperlink link = run.getHyperlink();
+ if (link != null) {
+ System.out.println(toStr(link, run.getRawText()));
+ }
+ }
}
}
// read such hyperlinks
System.out.println("- reading hyperlinks from the slide's shapes");
for (HSLFShape sh : slide.getShapes()) {
- HSLFHyperlink link = HSLFHyperlink.find(sh);
- if (link == null) continue;
- System.out.println(toStr(link, null));
+ if (sh instanceof HSLFSimpleShape) {
+ HSLFHyperlink link = ((HSLFSimpleShape)sh).getHyperlink();
+ if (link != null) {
+ System.out.println(toStr(link, null));
+ }
+ }
}
}
+ ppt.close();
}
}
static String toStr(HSLFHyperlink link, String rawText) {
//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.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), substring);
+ return String.format(Locale.ROOT, formatStr, link.getLabel(), link.getAddress(), link.getStartIndex(), link.getEndIndex(), rawText);
}
}
XSLFTextRun r2 = shape2.addNewTextParagraph().addNewTextRun();\r
XSLFHyperlink link2 = r2.createHyperlink();\r
r2.setText("Go to the second slide"); // visible text\r
- link2.setAddress(slide2); // link address\r
+ link2.linkToSlide(slide2); // link address\r
\r
\r
\r
* Returns an ImageRenderer for the PictureData\r
*\r
* @param graphics\r
- * @return\r
+ * @return the image renderer\r
*/\r
public static ImageRenderer getImageRenderer(Graphics2D graphics, String contentType) {\r
ImageRenderer renderer = (ImageRenderer)graphics.getRenderingHint(Drawable.IMAGE_RENDERER);\r
/**
* A PowerPoint hyperlink
*/
-public interface Hyperlink extends org.apache.poi.common.usermodel.Hyperlink {
+public interface Hyperlink<
+ S extends Shape<S,P>,
+ P extends TextParagraph<S,P,?>
+> extends org.apache.poi.common.usermodel.Hyperlink {
+ /**
+ * Link to an email
+ *
+ * @param emailAddress the email address
+ * @since POI 3.14-Beta2
+ */
+ void linkToEmail(String emailAddress);
+
+ /**
+ * Link to a web page / URL
+ *
+ * @param url the url
+ * @since POI 3.14-Beta2
+ */
+ void linkToUrl(String url);
+
+ /**
+ * Link to a slide in this slideshow
+ *
+ * @param slide the linked slide
+ * @since POI 3.14-Beta2
+ */
+ void linkToSlide(Slide<S,P> slide);
+
+ /**
+ * Link to the next slide (relative from the current)
+ *
+ * @since POI 3.14-Beta2
+ */
+ void linkToNextSlide();
+
+ /**
+ * Link to the previous slide (relative from the current)
+ *
+ * @since POI 3.14-Beta2
+ */
+ void linkToPreviousSlide();
+
+ /**
+ * Link to the first slide in this slideshow
+ *
+ * @since POI 3.14-Beta2
+ */
+ void linkToFirstSlide();
+
+ /**
+ * Link to the last slide in this slideshow
+ *
+ * @since POI 3.14-Beta2
+ */
+ void linkToLastSlide();
}
* the solid fill attribute from the underlying implementation
*/
void setFillColor(Color color);
+
+ /**
+ * Returns the hyperlink assigned to this shape
+ *
+ * @return the hyperlink assigned to this shape
+ * or <code>null</code> if not found.
+ *
+ * @since POI 3.14-Beta1
+ */
+ Hyperlink<S,P> getHyperlink();
+
+ /**
+ * Creates a hyperlink and asigns it to this shape.
+ * If the shape has already a hyperlink assigned, return it instead
+ *
+ * @return the hyperlink assigned to this shape
+ *
+ * @since POI 3.14-Beta1
+ */
+ Hyperlink<S,P> createHyperlink();
}
* Return the associated hyperlink
*
* @return the associated hyperlink or null if no hyperlink was set
+ *
+ * @since POI 3.14-Beta2
+ */
+ Hyperlink<?,?> getHyperlink();
+
+
+ /**
+ * Creates a new hyperlink and assigns it to this text run.
+ * If the text run has already a hyperlink assigned, return it instead
+ *
+ * @return the associated hyperlink
+ *
+ * @since POI 3.14-Beta2
*/
- Hyperlink getHyperlink();
+ Hyperlink<?,?> createHyperlink();
}
OTHER\r
}\r
\r
+ /**\r
+ * Returns the text contained in this text frame, which has been made safe\r
+ * for printing and other use.\r
+ * \r
+ * @return the text string for this textbox.\r
+ * \r
+ * @since POI 3.14-Beta2\r
+ */\r
+ String getText();\r
+ \r
/**\r
* Sets (overwrites) the current text.\r
* Uses the properties of the first paragraph / textrun.\r
* @return the last text run of the - potential split - text\r
*/\r
TextRun setText(String text);\r
+\r
+ /**\r
+ * Adds the supplied text onto the end of the TextParagraphs,\r
+ * creating a new RichTextRun for it to sit in.\r
+ *\r
+ * @param text the text string to be appended.\r
+ * @param newParagraph if true, a new paragraph will be added,\r
+ * which will contain the added text\r
+ *\r
+ * @since POI 3.14-Beta1\r
+ */\r
+ TextRun appendText(String text, boolean newParagraph);\r
\r
/**\r
* @return the TextParagraphs for this text box\r
==================================================================== */\r
package org.apache.poi.xslf.usermodel;\r
\r
+import java.net.URI;\r
+\r
+import org.apache.poi.openxml4j.opc.PackagePart;\r
+import org.apache.poi.openxml4j.opc.PackagePartName;\r
import org.apache.poi.openxml4j.opc.PackageRelationship;\r
import org.apache.poi.openxml4j.opc.TargetMode;\r
import org.apache.poi.sl.usermodel.Hyperlink;\r
+import org.apache.poi.sl.usermodel.Slide;\r
import org.apache.poi.util.Internal;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTHyperlink;\r
\r
-import java.net.URI;\r
-\r
-public class XSLFHyperlink implements Hyperlink {\r
- final XSLFTextRun _r;\r
+public class XSLFHyperlink implements Hyperlink<XSLFShape,XSLFTextParagraph> {\r
+ final XSLFSheet _sheet;\r
final CTHyperlink _link;\r
\r
- XSLFHyperlink(CTHyperlink link, XSLFTextRun r){\r
- _r = r;\r
+ XSLFHyperlink(CTHyperlink link, XSLFSheet sheet){\r
+ _sheet = sheet;\r
_link = link;\r
}\r
\r
}\r
\r
@Override\r
- public void setAddress(String address){\r
- XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();\r
- PackageRelationship rel =\r
- sheet.getPackagePart().\r
- addExternalRelationship(address, XSLFRelation.HYPERLINK.getRelation());\r
- _link.setId(rel.getId());\r
+ public void setAddress(String address) {\r
+ linkToUrl(address);\r
}\r
- \r
+\r
@Override\r
public String getAddress() {\r
- return getTargetURI().toASCIIString();\r
+ if (!_link.isSetId()) {\r
+ return _link.getAction();\r
+ }\r
+\r
+ String id = _link.getId();\r
+ URI targetURI = _sheet.getPackagePart().getRelationship(id).getTargetURI();\r
+ \r
+ return targetURI.toASCIIString();\r
}\r
\r
@Override\r
public String getLabel() {\r
return _link.getTooltip();\r
}\r
- \r
+\r
@Override\r
public void setLabel(String label) {\r
_link.setTooltip(label);\r
\r
@Override\r
public int getType() {\r
- // TODO: currently this just returns nonsense\r
- if ("ppaction://hlinksldjump".equals(_link.getAction())) {\r
+ String action = _link.getAction();\r
+ if (action == null) {\r
+ action = "";\r
+ }\r
+ if (action.equals("ppaction://hlinksldjump") || action.startsWith("ppaction://hlinkshowjump")) {\r
return LINK_DOCUMENT;\r
}\r
- return LINK_URL;\r
+ \r
+ String address = getAddress();\r
+ if (address == null) {\r
+ address = "";\r
+ }\r
+ if (address.startsWith("mailto:")) {\r
+ return LINK_EMAIL;\r
+ } else {\r
+ return LINK_URL;\r
+ }\r
}\r
- \r
- public void setAddress(XSLFSlide slide){\r
- XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();\r
+\r
+ @Override\r
+ public void linkToEmail(String emailAddress) {\r
+ linkToExternal("mailto:"+emailAddress);\r
+ setLabel(emailAddress);\r
+ }\r
+\r
+ @Override\r
+ public void linkToUrl(String url) {\r
+ linkToExternal(url);\r
+ setLabel(url);\r
+ }\r
+\r
+ private void linkToExternal(String url) {\r
+ PackagePart thisPP = _sheet.getPackagePart();\r
+ if (_link.isSetId() && !_link.getId().isEmpty()) {\r
+ thisPP.removeRelationship(_link.getId());\r
+ }\r
+ PackageRelationship rel = thisPP.addExternalRelationship(url, XSLFRelation.HYPERLINK.getRelation());\r
+ _link.setId(rel.getId());\r
+ if (_link.isSetAction()) {\r
+ _link.unsetAction();\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public void linkToSlide(Slide<XSLFShape,XSLFTextParagraph> slide) {\r
+ PackagePart thisPP = _sheet.getPackagePart();\r
+ PackagePartName otherPPN = ((XSLFSheet)slide).getPackagePart().getPartName();\r
+ if (_link.isSetId() && !_link.getId().isEmpty()) {\r
+ thisPP.removeRelationship(_link.getId());\r
+ }\r
PackageRelationship rel =\r
- sheet.getPackagePart().\r
- addRelationship(slide.getPackagePart().getPartName(),\r
- TargetMode.INTERNAL,\r
- XSLFRelation.SLIDE.getRelation());\r
+ thisPP.addRelationship(otherPPN, TargetMode.INTERNAL, XSLFRelation.SLIDE.getRelation());\r
_link.setId(rel.getId());\r
_link.setAction("ppaction://hlinksldjump");\r
}\r
\r
- @Internal\r
- public URI getTargetURI(){\r
- XSLFSheet sheet = _r.getParentParagraph().getParentShape().getSheet();\r
- String id = _link.getId();\r
- return sheet.getPackagePart().getRelationship(id).getTargetURI();\r
+ @Override\r
+ public void linkToNextSlide() {\r
+ linkToRelativeSlide("nextslide");\r
+ }\r
+\r
+ @Override\r
+ public void linkToPreviousSlide() {\r
+ linkToRelativeSlide("previousslide");\r
+ }\r
+\r
+ @Override\r
+ public void linkToFirstSlide() {\r
+ linkToRelativeSlide("firstslide");\r
+ }\r
+\r
+ @Override\r
+ public void linkToLastSlide() {\r
+ linkToRelativeSlide("lastslide");\r
+ }\r
+ \r
+ private void linkToRelativeSlide(String jump) {\r
+ PackagePart thisPP = _sheet.getPackagePart();\r
+ if (_link.isSetId() && !_link.getId().isEmpty()) {\r
+ thisPP.removeRelationship(_link.getId());\r
+ }\r
+ _link.setId("");\r
+ _link.setAction("ppaction://hlinkshowjump?jump="+jump);\r
}\r
-}\r
+}
\ No newline at end of file
import org.apache.poi.sl.usermodel.LineDecoration.DecorationShape;\r
import org.apache.poi.sl.usermodel.LineDecoration.DecorationSize;\r
import org.apache.poi.sl.usermodel.PaintStyle;\r
-import org.apache.poi.sl.usermodel.Placeholder;\r
import org.apache.poi.sl.usermodel.PaintStyle.SolidPaint;\r
+import org.apache.poi.sl.usermodel.Placeholder;\r
import org.apache.poi.sl.usermodel.ShapeType;\r
import org.apache.poi.sl.usermodel.SimpleShape;\r
import org.apache.poi.sl.usermodel.StrokeStyle;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineEndProperties;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineProperties;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTLineStyleList;\r
+import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTOuterShadowEffect;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTPoint2D;\r
import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D;\r
public void setPlaceholder(Placeholder placeholder) {\r
super.setPlaceholder(placeholder);\r
}\r
+ \r
+ @Override\r
+ public XSLFHyperlink getHyperlink() {\r
+ CTNonVisualDrawingProps cNvPr = getCNvPr();\r
+ if (!cNvPr.isSetHlinkClick()) {\r
+ return null;\r
+ }\r
+ return new XSLFHyperlink(cNvPr.getHlinkClick(), getSheet());\r
+ }\r
+ \r
+ @Override\r
+ public XSLFHyperlink createHyperlink() {\r
+ XSLFHyperlink hl = getHyperlink();\r
+ if (hl == null) {\r
+ CTNonVisualDrawingProps cNvPr = getCNvPr();\r
+ hl = new XSLFHyperlink(cNvPr.addNewHlinkClick(), getSheet());\r
+ }\r
+ return hl;\r
+ }\r
}\r
}\r
}\r
}\r
+ \r
+ /**\r
+ * Helper method for appending text and keeping paragraph and character properties.\r
+ * The character properties are moved to the end paragraph marker\r
+ */\r
+ /* package */ void clearButKeepProperties() {\r
+ CTTextParagraph thisP = getXmlObject();\r
+ for (int i=thisP.sizeOfBrArray(); i>0; i--) {\r
+ thisP.removeBr(i-1);\r
+ }\r
+ for (int i=thisP.sizeOfFldArray(); i>0; i--) {\r
+ thisP.removeFld(i-1);\r
+ }\r
+ if (!_runs.isEmpty()) {\r
+ int size = _runs.size();\r
+ thisP.setEndParaRPr(_runs.get(size-1).getRPr());\r
+ for (int i=size; i>0; i--) {\r
+ thisP.removeR(i-1);\r
+ }\r
+ _runs.clear();\r
+ }\r
+ }\r
}\r
return "[" + getClass() + "]" + getRawText();\r
}\r
\r
+ @Override\r
public XSLFHyperlink createHyperlink(){\r
- XSLFHyperlink link = new XSLFHyperlink(_r.getRPr().addNewHlinkClick(), this);\r
- return link;\r
+ XSLFHyperlink hl = getHyperlink();\r
+ if (hl == null) {\r
+ hl = new XSLFHyperlink(_r.getRPr().addNewHlinkClick(), _p.getParentShape().getSheet());\r
+ }\r
+ return hl;\r
}\r
\r
@Override\r
public XSLFHyperlink getHyperlink(){\r
if(!_r.getRPr().isSetHlinkClick()) return null;\r
-\r
-\r
- return new XSLFHyperlink(_r.getRPr().getHlinkClick(), this);\r
+ return new XSLFHyperlink(_r.getRPr().getHlinkClick(), _p.getParentShape().getSheet());\r
}\r
\r
private boolean fetchCharacterProperty(CharacterPropertyFetcher<?> fetcher){\r
return getTextParagraphs().iterator();
}
- /**
- *
- * @return text contained within this shape or empty string
- */
+ @Override
public String getText() {
StringBuilder out = new StringBuilder();
for (XSLFTextParagraph p : _paragraphs) {
@Override
public XSLFTextRun setText(String text) {
- // copy properties from first paragraph / textrun
+ // calling clearText or setting to a new Array leads to a XmlValueDisconnectedException
+ if (!_paragraphs.isEmpty()) {
+ CTTextBody txBody = getTextBody(false);
+ int cntPs = txBody.sizeOfPArray();
+ for (int i = cntPs; i > 1; i--) {
+ txBody.removeP(i-1);
+ _paragraphs.remove(i-1);
+ }
+
+ _paragraphs.get(0).clearButKeepProperties();
+ }
+
+ return appendText(text, false);
+ }
+
+ @Override
+ public XSLFTextRun appendText(String text, boolean newParagraph) {
+ if (text == null) return null;
+
+ // copy properties from last paragraph / textrun or paragraph end marker
CTTextParagraphProperties pPr = null;
CTTextCharacterProperties rPr = null;
- if (!_paragraphs.isEmpty()) {
- XSLFTextParagraph p0 = _paragraphs.get(0);
- pPr = p0.getXmlObject().getPPr();
- if (!p0.getTextRuns().isEmpty()) {
- XSLFTextRun r0 = p0.getTextRuns().get(0);
+
+ boolean firstPara;
+ XSLFTextParagraph para;
+ if (_paragraphs.isEmpty()) {
+ firstPara = false;
+ para = null;
+ } else {
+ firstPara = !newParagraph;
+ para = _paragraphs.get(_paragraphs.size()-1);
+ CTTextParagraph ctp = para.getXmlObject();
+ pPr = ctp.getPPr();
+ List<XSLFTextRun> runs = para.getTextRuns();
+ if (!runs.isEmpty()) {
+ XSLFTextRun r0 = runs.get(runs.size()-1);
rPr = r0.getXmlObject().getRPr();
+ } else if (ctp.isSetEndParaRPr()) {
+ rPr = ctp.getEndParaRPr();
}
}
-
- // can't call clearText otherwise we receive a XmlValueDisconnectedException
- _paragraphs.clear();
- CTTextBody txBody = getTextBody(true);
- int cntPs = txBody.sizeOfPArray();
- // split text by paragraph and new line char
- XSLFTextRun r = null;
- for (String paraText : text.split("\\r\\n?|\\n")) {
- XSLFTextParagraph para = addNewTextParagraph();
- if (pPr != null) {
- para.getXmlObject().setPPr(pPr);
+ XSLFTextRun run = null;
+ for (String lineTxt : text.split("\\r\\n?|\\n")) {
+ if (!firstPara) {
+ if (para != null && para.getXmlObject().isSetEndParaRPr()) {
+ para.getXmlObject().unsetEndParaRPr();
+ }
+ para = addNewTextParagraph();
+ if (pPr != null) {
+ para.getXmlObject().setPPr(pPr);
+ }
}
- boolean first = true;
- for (String runText : paraText.split("[\u000b]")) {
- if (!first) {
+ boolean firstRun = true;
+ for (String runText : lineTxt.split("[\u000b]")) {
+ if (!firstRun) {
para.addLineBreak();
}
- r = para.addNewTextRun();
- r.setText(runText);
+ run = para.addNewTextRun();
+ run.setText(runText);
if (rPr != null) {
- r.getXmlObject().setRPr(rPr);
+ run.getXmlObject().setRPr(rPr);
}
- first = false;
+ firstRun = false;
}
+ firstPara = false;
}
- // simply setting a new pArray leads to XmlValueDisconnectedException
- for (int i = cntPs-1; i >= 0; i--) {
- txBody.removeP(i);
- }
-
- return r;
+ assert(run != null);
+ return run;
}
@Override
import static org.junit.Assert.assertEquals;\r
import static org.junit.Assert.assertNotNull;\r
\r
+import java.awt.geom.Rectangle2D;\r
import java.io.IOException;\r
-import java.net.URI;\r
import java.util.List;\r
\r
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;\r
import org.apache.poi.openxml4j.opc.PackageRelationship;\r
import org.apache.poi.openxml4j.opc.TargetMode;\r
+import org.apache.poi.sl.usermodel.Hyperlink;\r
import org.apache.poi.xslf.XSLFTestDataSamples;\r
import org.junit.Test;\r
\r
-/**\r
- * @author Yegor Kozlov\r
- */\r
public class TestXSLFHyperlink {\r
\r
@Test\r
assertEquals("Web Page", cell1.getText());\r
XSLFHyperlink link1 = cell1.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
assertNotNull(link1);\r
- assertEquals(URI.create("http://poi.apache.org/"), link1.getTargetURI());\r
+ assertEquals("http://poi.apache.org/", link1.getAddress());\r
\r
XSLFTableCell cell2 = tbl.getRows().get(2).getCells().get(0);\r
assertEquals("Place in this document", cell2.getText());\r
XSLFHyperlink link2 = cell2.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
assertNotNull(link2);\r
- assertEquals(URI.create("/ppt/slides/slide2.xml"), link2.getTargetURI());\r
+ assertEquals("/ppt/slides/slide2.xml", link2.getAddress());\r
\r
XSLFTableCell cell3 = tbl.getRows().get(3).getCells().get(0);\r
assertEquals("Email", cell3.getText());\r
XSLFHyperlink link3 = cell3.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
assertNotNull(link3);\r
- assertEquals(URI.create("mailto:dev@poi.apache.org?subject=Hi%20There"), link3.getTargetURI());\r
+ assertEquals("mailto:dev@poi.apache.org?subject=Hi%20There", link3.getAddress());\r
\r
ppt.close();\r
}\r
r1.setText("Web Page");\r
XSLFHyperlink link1 = r1.createHyperlink();\r
link1.setAddress("http://poi.apache.org/");\r
- assertEquals(URI.create("http://poi.apache.org/"), link1.getTargetURI());\r
+ assertEquals("http://poi.apache.org/", link1.getAddress());\r
assertEquals(numRel + 1, slide1.getPackagePart().getRelationships().size());\r
\r
String id1 = link1.getXmlObject().getId();\r
XSLFTextRun r2 = sh2.addNewTextParagraph().addNewTextRun();\r
r2.setText("Place in this document");\r
XSLFHyperlink link2 = r2.createHyperlink();\r
- link2.setAddress(slide2);\r
- assertEquals(URI.create("/ppt/slides/slide2.xml"), link2.getTargetURI());\r
+ link2.linkToSlide(slide2);\r
+ assertEquals("/ppt/slides/slide2.xml", link2.getAddress());\r
assertEquals(numRel + 2, slide1.getPackagePart().getRelationships().size());\r
\r
String id2 = link2.getXmlObject().getId();\r
\r
ppt.close();\r
}\r
+\r
+\r
+ @Test\r
+ public void bug47291() throws IOException {\r
+ Rectangle2D anchor = new Rectangle2D.Double(100,100,100,100);\r
+ XMLSlideShow ppt1 = new XMLSlideShow();\r
+ XSLFSlide slide1 = ppt1.createSlide();\r
+ XSLFTextBox tb1 = slide1.createTextBox();\r
+ tb1.setAnchor(anchor);\r
+ XSLFTextRun r1 = tb1.setText("page1");\r
+ XSLFHyperlink hl1 = r1.createHyperlink();\r
+ hl1.linkToEmail("dev@poi.apache.org");\r
+ XSLFTextBox tb2 = ppt1.createSlide().createTextBox();\r
+ tb2.setAnchor(anchor);\r
+ XSLFTextRun r2 = tb2.setText("page2");\r
+ XSLFHyperlink hl2 = r2.createHyperlink();\r
+ hl2.linkToLastSlide();\r
+ XSLFSlide sl3 = ppt1.createSlide();\r
+ XSLFTextBox tb3 = sl3.createTextBox();\r
+ tb3.setAnchor(anchor);\r
+ tb3.setText("text1 ");\r
+ XSLFTextRun r3 = tb3.appendText("lin\u000bk", false);\r
+ tb3.appendText(" text2", false);\r
+ XSLFHyperlink hl3 = r3.createHyperlink();\r
+ hl3.linkToSlide(slide1);\r
+ XSLFTextBox tb4 = ppt1.createSlide().createTextBox();\r
+ tb4.setAnchor(anchor);\r
+ XSLFTextRun r4 = tb4.setText("page4");\r
+ XSLFHyperlink hl4 = r4.createHyperlink();\r
+ hl4.linkToUrl("http://poi.apache.org");\r
+ XSLFTextBox tb5 = ppt1.createSlide().createTextBox();\r
+ tb5.setAnchor(anchor);\r
+ tb5.setText("page5");\r
+ XSLFHyperlink hl5 = tb5.createHyperlink();\r
+ hl5.linkToFirstSlide();\r
+\r
+ XMLSlideShow ppt2 = XSLFTestDataSamples.writeOutAndReadBack(ppt1);\r
+ ppt1.close();\r
+\r
+ List<XSLFSlide> slides = ppt2.getSlides();\r
+ tb1 = (XSLFTextBox)slides.get(0).getShapes().get(0);\r
+ hl1 = tb1.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
+ assertNotNull(hl1);\r
+ assertEquals("dev@poi.apache.org", hl1.getLabel());\r
+ assertEquals(Hyperlink.LINK_EMAIL, hl1.getType());\r
+\r
+ tb2 = (XSLFTextBox)slides.get(1).getShapes().get(0);\r
+ hl2 = tb2.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
+ assertNotNull(hl2);\r
+ assertEquals("lastslide", hl2.getXmlObject().getAction().split("=")[1]);\r
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl2.getType());\r
+\r
+ tb3 = (XSLFTextBox)slides.get(2).getShapes().get(0);\r
+ hl3 = tb3.getTextParagraphs().get(0).getTextRuns().get(3).getHyperlink();\r
+ assertNotNull(hl3);\r
+ assertEquals("/ppt/slides/slide1.xml", hl3.getAddress());\r
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl3.getType());\r
+\r
+ tb4 = (XSLFTextBox)slides.get(3).getShapes().get(0);\r
+ hl4 = tb4.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();\r
+ assertNotNull(hl4);\r
+ assertEquals("http://poi.apache.org", hl4.getLabel());\r
+ assertEquals(Hyperlink.LINK_URL, hl4.getType());\r
+\r
+ tb5 = (XSLFTextBox)slides.get(4).getShapes().get(0);\r
+ hl5 = tb5.getHyperlink();\r
+ assertNotNull(hl5);\r
+ assertEquals("firstslide", hl5.getXmlObject().getAction().split("=")[1]);\r
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl5.getType());\r
+ \r
+ ppt2.close();\r
+ }\r
}
\ No newline at end of file
if(_exEmbed == null){
HSLFSlideShow ppt = getSheet().getSlideShow();
- ExObjList lst = ppt.getDocumentRecord().getExObjList();
+ ExObjList lst = ppt.getDocumentRecord().getExObjList(false);
if(lst == null){
logger.log(POILogger.WARN, "ExObjList not found");
return null;
* Returns the DocumentAtom of this Document
*/
public DocumentAtom getDocumentAtom() { return documentAtom; }
+
/**
* Returns the Environment of this Notes, which lots of
- * settings for the document in it
+ * settings for the document in it
*/
public Environment getEnvironment() { return environment; }
+
/**
* Returns the PPDrawingGroup, which holds an Escher Structure
- * that contains information on pictures in the slides.
+ * that contains information on pictures in the slides.
*/
public PPDrawingGroup getPPDrawingGroup() { return ppDrawing; }
+
/**
* Returns the ExObjList, which holds the references to
- * external objects used in the slides. This may be null, if
- * there are no external references.
+ * external objects used in the slides. This may be null, if
+ * there are no external references.
+ *
+ * @param create if true, create an ExObjList if it doesn't exist
*/
- public ExObjList getExObjList() { return exObjList; }
+ public ExObjList getExObjList(boolean create) {
+ if (exObjList == null && create) {
+ exObjList = new ExObjList();
+ addChildAfter(exObjList, getDocumentAtom());
+ }
+ return exObjList;
+ }
/**
* Returns all the SlideListWithTexts that are defined for
linkDetailsB.setText(url);
}
}
- public void setLinkURL(String url, int options) {
+
+ public void setLinkOptions(int options) {
if(linkDetailsB != null) {
- linkDetailsB.setText(url);
linkDetailsB.setOptions(options);
}
}
linkDetailsA.setText(title);
}
}
-
+
/**
* Get the link details (field A)
*/
import java.util.ListIterator;
import org.apache.poi.hslf.record.ExHyperlink;
+import org.apache.poi.hslf.record.ExHyperlinkAtom;
import org.apache.poi.hslf.record.ExObjList;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
import org.apache.poi.hslf.record.InteractiveInfo;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
import org.apache.poi.sl.usermodel.Hyperlink;
+import org.apache.poi.sl.usermodel.Slide;
/**
* Represents a hyperlink in a PowerPoint document
*/
-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;
- public static final byte LINK_LASTSLIDE = InteractiveInfoAtom.LINK_LastSlide;
- public static final byte LINK_SLIDENUMBER = InteractiveInfoAtom.LINK_SlideNumber;
- public static final byte LINK_URL = InteractiveInfoAtom.LINK_Url;
- public static final byte LINK_NULL = InteractiveInfoAtom.LINK_NULL;
-
- private int id=-1;
- private int type;
- private String address;
- private String label;
- private int startIndex, endIndex;
+public final class HSLFHyperlink implements Hyperlink<HSLFShape,HSLFTextParagraph> {
+ private final ExHyperlink exHyper;
+ private final InteractiveInfo info;
+ private TxInteractiveInfoAtom txinfo;
+
+ protected HSLFHyperlink(ExHyperlink exHyper, InteractiveInfo info) {
+ this.info = info;
+ this.exHyper = exHyper;
+ }
+
+ public ExHyperlink getExHyperlink() {
+ return exHyper;
+ }
+
+ public InteractiveInfo getInfo() {
+ return info;
+ }
+
+ public TxInteractiveInfoAtom getTextRunInfo() {
+ return txinfo;
+ }
+
+ protected void setTextRunInfo(TxInteractiveInfoAtom txinfo) {
+ this.txinfo = txinfo;
+ }
+
+ /**
+ * Creates a new Hyperlink and assign it to a shape
+ * This is only a helper method - use {@link HSLFSimpleShape#createHyperlink()} instead!
+ *
+ * @param shape the shape which receives the hyperlink
+ * @return the new hyperlink
+ *
+ * @see HSLFShape#createHyperlink()
+ */
+ /* package */ static HSLFHyperlink createHyperlink(HSLFSimpleShape shape) {
+ // TODO: check if a hyperlink already exists
+ ExHyperlink exHyper = new ExHyperlink();
+ int linkId = shape.getSheet().getSlideShow().addToObjListAtom(exHyper);
+ ExHyperlinkAtom obj = exHyper.getExHyperlinkAtom();
+ obj.setNumber(linkId);
+ InteractiveInfo info = new InteractiveInfo();
+ info.getInteractiveInfoAtom().setHyperlinkID(linkId);
+ HSLFEscherClientDataRecord cldata = shape.getClientData(true);
+ cldata.addChild(info);
+ HSLFHyperlink hyper = new HSLFHyperlink(exHyper, info);
+ hyper.linkToNextSlide();
+ shape.setHyperlink(hyper);
+ return hyper;
+ }
+
+ /**
+ * Creates a new Hyperlink for a textrun.
+ * This is only a helper method - use {@link HSLFTextRun#createHyperlink()} instead!
+ *
+ * @param run the run which receives the hyperlink
+ * @return the new hyperlink
+ *
+ * @see HSLFTextRun#createHyperlink()
+ */
+ /* package */ static HSLFHyperlink createHyperlink(HSLFTextRun run) {
+ // TODO: check if a hyperlink already exists
+ ExHyperlink exHyper = new ExHyperlink();
+ int linkId = run.getTextParagraph().getSheet().getSlideShow().addToObjListAtom(exHyper);
+ ExHyperlinkAtom obj = exHyper.getExHyperlinkAtom();
+ obj.setNumber(linkId);
+ InteractiveInfo info = new InteractiveInfo();
+ info.getInteractiveInfoAtom().setHyperlinkID(linkId);
+ // don't add the hyperlink now to text paragraph records
+ // this will be done, when the paragraph is saved
+ HSLFHyperlink hyper = new HSLFHyperlink(exHyper, info);
+ hyper.linkToNextSlide();
+
+ TxInteractiveInfoAtom txinfo = new TxInteractiveInfoAtom();
+ int startIdx = run.getTextParagraph().getStartIdxOfTextRun(run);
+ int endIdx = startIdx + run.getLength();
+ txinfo.setStartIndex(startIdx);
+ txinfo.setEndIndex(endIdx);
+ hyper.setTextRunInfo(txinfo);
+
+ run.setHyperlink(hyper);
+ return hyper;
+ }
+
/**
* Gets the type of the hyperlink action.
*/
@Override
public int getType() {
- return type;
- }
-
- public void setType(int val) {
- type = val;
- switch(type){
- case LINK_NEXTSLIDE:
- label = "NEXT";
- address = "1,-1,NEXT";
- break;
- case LINK_PREVIOUSSLIDE:
- label = "PREV";
- address = "1,-1,PREV";
- break;
- case LINK_FIRSTSLIDE:
- label = "FIRST";
- address = "1,-1,FIRST";
- break;
- case LINK_LASTSLIDE:
- label = "LAST";
- address = "1,-1,LAST";
- break;
- case LINK_SLIDENUMBER:
- break;
- default:
- label = "";
- address = "";
- break;
+ switch (info.getInteractiveInfoAtom().getHyperlinkType()) {
+ case InteractiveInfoAtom.LINK_Url:
+ return (exHyper.getLinkURL().startsWith("mailto:")) ? LINK_EMAIL : LINK_URL;
+ case InteractiveInfoAtom.LINK_NextSlide:
+ case InteractiveInfoAtom.LINK_PreviousSlide:
+ case InteractiveInfoAtom.LINK_FirstSlide:
+ case InteractiveInfoAtom.LINK_LastSlide:
+ case InteractiveInfoAtom.LINK_SlideNumber:
+ return LINK_DOCUMENT;
+ case InteractiveInfoAtom.LINK_CustomShow:
+ case InteractiveInfoAtom.LINK_OtherPresentation:
+ case InteractiveInfoAtom.LINK_OtherFile:
+ return LINK_FILE;
+ default:
+ case InteractiveInfoAtom.LINK_NULL:
+ return -1;
}
}
@Override
- public String getAddress() {
- return address;
+ public void linkToEmail(String emailAddress) {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
+ iia.setJump(InteractiveInfoAtom.JUMP_NONE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
+ exHyper.setLinkURL("mailto:"+emailAddress);
+ exHyper.setLinkTitle(emailAddress);
+ exHyper.setLinkOptions(0x10);
}
- public void setAddress(HSLFSlide slide) {
- String href = slide._getSheetNumber() + ","+slide.getSlideNumber()+",Slide " + slide.getSlideNumber();
- setAddress(href);;
- setLabel("Slide " + slide.getSlideNumber());
- setType(HSLFHyperlink.LINK_SLIDENUMBER);
+ @Override
+ public void linkToUrl(String url) {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
+ iia.setJump(InteractiveInfoAtom.JUMP_NONE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
+ exHyper.setLinkURL(url);
+ exHyper.setLinkTitle(url);
+ exHyper.setLinkOptions(0x10);
}
@Override
- public void setAddress(String str) {
- address = str;
+ public void linkToSlide(Slide<HSLFShape,HSLFTextParagraph> slide) {
+ assert(slide instanceof HSLFSlide);
+ HSLFSlide sl = (HSLFSlide)slide;
+ int slideNum = slide.getSlideNumber();
+ String alias = "Slide "+slideNum;
+
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
+ iia.setJump(InteractiveInfoAtom.JUMP_NONE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber);
+
+ linkToDocument(sl._getSheetNumber(),slideNum,alias,0x30);
}
- public int getId() {
- return id;
+ @Override
+ public void linkToNextSlide() {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ iia.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide);
+
+ linkToDocument(1,-1,"NEXT",0x10);
}
- public void setId(int id) {
- this.id = id;
+ @Override
+ public void linkToPreviousSlide() {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ iia.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide);
+
+ linkToDocument(1,-1,"PREV",0x10);
+ }
+
+ @Override
+ public void linkToFirstSlide() {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ iia.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide);
+
+ linkToDocument(1,-1,"FIRST",0x10);
+ }
+
+ @Override
+ public void linkToLastSlide() {
+ InteractiveInfoAtom iia = info.getInteractiveInfoAtom();
+ iia.setAction(InteractiveInfoAtom.ACTION_JUMP);
+ iia.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE);
+ iia.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide);
+
+ linkToDocument(1,-1,"LAST",0x10);
+ }
+
+ private void linkToDocument(int sheetNumber, int slideNumber, String alias, int options) {
+ exHyper.setLinkURL(sheetNumber+","+slideNumber+","+alias);
+ exHyper.setLinkTitle(alias);
+ exHyper.setLinkOptions(options);
+ }
+
+ @Override
+ public String getAddress() {
+ return exHyper.getLinkURL();
+ }
+
+ @Override
+ public void setAddress(String str) {
+ exHyper.setLinkURL(str);
+ }
+
+ public int getId() {
+ return exHyper.getExHyperlinkAtom().getNumber();
}
@Override
public String getLabel() {
- return label;
+ return exHyper.getLinkTitle();
}
@Override
- public void setLabel(String str) {
- label = str;
+ public void setLabel(String label) {
+ exHyper.setLinkTitle(label);
}
/**
* @return the beginning character position
*/
public int getStartIndex() {
- return startIndex;
+ return (txinfo == null) ? -1 : txinfo.getStartIndex();
}
/**
* @param startIndex the beginning character position
*/
public void setStartIndex(int startIndex) {
- this.startIndex = startIndex;
+ if (txinfo != null) {
+ txinfo.setStartIndex(startIndex);
+ }
}
-
+
/**
* Gets the ending character position
*
* @return the ending character position
*/
public int getEndIndex() {
- return endIndex;
+ return (txinfo == null) ? -1 : txinfo.getEndIndex();
}
/**
* @param endIndex the ending character position
*/
public void setEndIndex(int endIndex) {
- this.endIndex = endIndex;
+ if (txinfo != null) {
+ txinfo.setEndIndex(endIndex);
+ }
}
-
+
/**
* Find hyperlinks in a text shape
*
* @return found hyperlinks
*/
@SuppressWarnings("resource")
- public static List<HSLFHyperlink> find(List<HSLFTextParagraph> paragraphs){
+ protected static List<HSLFHyperlink> find(List<HSLFTextParagraph> paragraphs){
List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>();
if (paragraphs == null || paragraphs.isEmpty()) return lst;
HSLFTextParagraph firstPara = paragraphs.get(0);
-
+
HSLFSlideShow ppt = firstPara.getSheet().getSlideShow();
//document-level container which stores info about all links in a presentation
- ExObjList exobj = ppt.getDocumentRecord().getExObjList();
+ ExObjList exobj = ppt.getDocumentRecord().getExObjList(false);
if (exobj != null) {
Record[] records = firstPara.getRecords();
find(Arrays.asList(records), exobj, lst);
* @return found hyperlink or <code>null</code>
*/
@SuppressWarnings("resource")
- public static HSLFHyperlink find(HSLFShape shape){
+ protected static HSLFHyperlink find(HSLFShape shape){
HSLFSlideShow ppt = shape.getSheet().getSlideShow();
//document-level container which stores info about all links in a presentation
- ExObjList exobj = ppt.getDocumentRecord().getExObjList();
+ ExObjList exobj = ppt.getDocumentRecord().getExObjList(false);
HSLFEscherClientDataRecord cldata = shape.getClientData(false);
if (exobj != null && cldata != null) {
InteractiveInfo hldr = (InteractiveInfo)r;
InteractiveInfoAtom info = hldr.getInteractiveInfoAtom();
int id = info.getHyperlinkID();
- ExHyperlink linkRecord = exobj.get(id);
- if (linkRecord == null) {
+ ExHyperlink exHyper = exobj.get(id);
+ if (exHyper == null) {
continue;
}
-
- HSLFHyperlink link = new HSLFHyperlink();
- link.setId(id);
- link.setType(info.getAction());
- link.setLabel(linkRecord.getLinkTitle());
- link.setAddress(linkRecord.getLinkURL());
+
+ HSLFHyperlink link = new HSLFHyperlink(exHyper, hldr);
out.add(link);
if (iter.hasNext()) {
iter.previous();
continue;
}
- TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)r;
- link.setStartIndex(txinfo.getStartIndex());
- link.setEndIndex(txinfo.getEndIndex());
+ link.setTextRunInfo((TxInteractiveInfoAtom)r);
}
}
}
import org.apache.poi.ddf.EscherClientAnchorRecord;
import org.apache.poi.ddf.EscherColorRef;
import org.apache.poi.ddf.EscherContainerRecord;
-import org.apache.poi.ddf.EscherOptRecord;
import org.apache.poi.ddf.EscherProperties;
import org.apache.poi.ddf.EscherProperty;
import org.apache.poi.ddf.EscherRecord;
* in points (72 points = 1 inch).
* </p>
* <p>
- *
- * @author Yegor Kozlov
*/
public abstract class HSLFShape implements Shape<HSLFShape,HSLFTextParagraph> {
* Fill
*/
protected HSLFFill _fill;
-
+
/**
* Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document.
*
return getFill().getFillStyle();
}
- /**
- * Returns the hyperlink assigned to this shape
- *
- * @return the hyperlink assigned to this shape
- * or <code>null</code> if not found.
- */
- public HSLFHyperlink getHyperlink(){
- return HSLFHyperlink.find(this);
- }
-
public void draw(Graphics2D graphics){
logger.log(POILogger.INFO, "Rendering " + getShapeName());
}
if (trs == null) return;
for (List<HSLFTextParagraph> ltp : trs) {
HSLFTextParagraph.supplySheet(ltp, this);
+ HSLFTextParagraph.applyHyperlinks(ltp);
}
}
EscherContainerRecord sp = (EscherContainerRecord) it.next();
HSLFShape sh = HSLFShapeFactory.createShape(sp, null);
sh.setSheet(this);
+
+ if (sh instanceof HSLFSimpleShape) {
+ HSLFHyperlink link = HSLFHyperlink.find(sh);
+ if (link != null) {
+ ((HSLFSimpleShape)sh).setHyperlink(link);
+ }
+ }
+
shapeList.add(sh);
}
import org.apache.poi.ddf.EscherSpRecord;
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.record.HSLFEscherClientDataRecord;
-import org.apache.poi.hslf.record.InteractiveInfo;
-import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.Record;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
public final static double DEFAULT_LINE_WIDTH = 0.75;
+ /**
+ * Hyperlink
+ */
+ protected HSLFHyperlink _hyperlink;
+
/**
* Create a SimpleShape object and initialize it from the supplied Record container.
*
getFill().setForegroundColor(color);
}
- public void setHyperlink(HSLFHyperlink link){
- if(link.getId() == -1){
- throw new HSLFException("You must call SlideShow.addHyperlink(Hyperlink link) first");
- }
-
- InteractiveInfo info = new InteractiveInfo();
- InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
-
- switch(link.getType()){
- case HSLFHyperlink.LINK_FIRSTSLIDE:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_FIRSTSLIDE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_FirstSlide);
- break;
- case HSLFHyperlink.LINK_LASTSLIDE:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_LASTSLIDE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_LastSlide);
- break;
- case HSLFHyperlink.LINK_NEXTSLIDE:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_NEXTSLIDE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_NextSlide);
- break;
- case HSLFHyperlink.LINK_PREVIOUSSLIDE:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_JUMP);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_PREVIOUSSLIDE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_PreviousSlide);
- break;
- case HSLFHyperlink.LINK_URL:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_Url);
- break;
- case HSLFHyperlink.LINK_SLIDENUMBER:
- infoAtom.setAction(InteractiveInfoAtom.ACTION_HYPERLINK);
- infoAtom.setJump(InteractiveInfoAtom.JUMP_NONE);
- infoAtom.setHyperlinkType(InteractiveInfoAtom.LINK_SlideNumber);
- break;
- default:
- logger.log(POILogger.WARN, "Ignore unknown hyperlink type : "+link.getLabel());
- break;
- }
-
- infoAtom.setHyperlinkID(link.getId());
-
- HSLFEscherClientDataRecord cldata = getClientData(true);
- cldata.addChild(info);
- }
-
public Guide getAdjustValue(String name) {
if (name == null || !name.matches("adj([1-9]|10)?")) {
throw new IllegalArgumentException("Adjust value '"+name+"' not supported.");
}
}
}
+
+ @Override
+ public HSLFHyperlink getHyperlink(){
+ return _hyperlink;
+ }
+
+ @Override
+ public HSLFHyperlink createHyperlink() {
+ if (_hyperlink == null) {
+ _hyperlink = HSLFHyperlink.createHyperlink(this);
+ }
+ return _hyperlink;
+ }
+
+ /**
+ * Sets the hyperlink - used when the document is parsed
+ *
+ * @param link the hyperlink
+ */
+ protected void setHyperlink(HSLFHyperlink link) {
+ _hyperlink = link;
+ }
}
\ No newline at end of file
return objectId;
}
- /**
- * Add a hyperlink to this presentation
- *
- * @return 0-based index of the hyperlink
- */
- public int addHyperlink(HSLFHyperlink link) {
- ExHyperlink ctrl = new ExHyperlink();
- ExHyperlinkAtom obj = ctrl.getExHyperlinkAtom();
- if(link.getType() == HSLFHyperlink.LINK_SLIDENUMBER) {
- ctrl.setLinkURL(link.getAddress(), 0x30);
- } else {
- ctrl.setLinkURL(link.getAddress());
- }
- ctrl.setLinkTitle(link.getLabel());
-
- int objectId = addToObjListAtom(ctrl);
- link.setId(objectId);
- obj.setNumber(objectId);
-
- return objectId;
- }
-
/**
* Add a embedded object to this presentation
*
}
protected int addToObjListAtom(RecordContainer exObj) {
- ExObjList lst = (ExObjList) _documentRecord.findFirstOfType(RecordTypes.ExObjList.typeID);
- if (lst == null) {
- lst = new ExObjList();
- _documentRecord.addChildAfter(lst, _documentRecord.getDocumentAtom());
- }
+ ExObjList lst = getDocumentRecord().getExObjList(true);
ExObjListAtom objAtom = lst.getExObjListAtom();
// increment the object ID seed
int objectId = (int) objAtom.getObjectIDSeed() + 1;
import java.awt.Color;\r
import java.io.IOException;\r
import java.util.ArrayList;\r
-import java.util.Arrays;\r
import java.util.Iterator;\r
import java.util.List;\r
\r
import org.apache.poi.hslf.record.ColorSchemeAtom;\r
import org.apache.poi.hslf.record.EscherTextboxWrapper;\r
import org.apache.poi.hslf.record.FontCollection;\r
+import org.apache.poi.hslf.record.InteractiveInfo;\r
import org.apache.poi.hslf.record.MasterTextPropAtom;\r
import org.apache.poi.hslf.record.OutlineTextRefAtom;\r
import org.apache.poi.hslf.record.PPDrawing;\r
import org.apache.poi.hslf.record.TextHeaderAtom;\r
import org.apache.poi.hslf.record.TextRulerAtom;\r
import org.apache.poi.hslf.record.TextSpecInfoAtom;\r
+import org.apache.poi.hslf.record.TxInteractiveInfoAtom;\r
import org.apache.poi.sl.draw.DrawPaint;\r
import org.apache.poi.sl.usermodel.AutoNumberingScheme;\r
import org.apache.poi.sl.usermodel.PaintStyle;\r
private StyleTextProp9Atom styleTextProp9Atom;\r
\r
private boolean _dirty = false;\r
- \r
+\r
private final List<HSLFTextParagraph> parentList;\r
\r
/**\r
* Setting a master style reference\r
*\r
* @param paragraphStyle the master style reference\r
- * \r
+ *\r
* @since POI 3.14-Beta1\r
*/\r
@Internal\r
/* package */ void setMasterStyleReference(TextPropCollection paragraphStyle) {\r
_paragraphStyle = paragraphStyle;\r
}\r
- \r
+\r
/**\r
* Supply the Sheet we belong to, which might have an assigned SlideShow\r
* Also passes it on to our child RichTextRuns\r
}\r
\r
assert(sheet.getSlideShow() != null);\r
- applyHyperlinks(paragraphs);\r
}\r
- \r
+\r
/**\r
* Supply the Sheet we belong to, which might have an assigned SlideShow\r
* Also passes it on to our child RichTextRuns\r
}\r
}\r
}\r
- \r
+\r
@Override\r
public HSLFTextShape getParentShape() {\r
return _parentShape;\r
if (_runs.isEmpty()) {\r
return null;\r
}\r
- \r
+\r
SolidPaint sp = _runs.get(0).getFontColor();\r
if(sp == null) {\r
return null;\r
}\r
- \r
+\r
return DrawPaint.applyColorTransform(sp.getSolidColor());\r
}\r
\r
* Fetch the value of the given Paragraph related TextProp. Returns null if\r
* that TextProp isn't present. If the TextProp isn't present, the value\r
* from the appropriate Master Sheet will apply.\r
- * \r
+ *\r
* The propName can be a comma-separated list, in case multiple equivalent values\r
* are queried\r
*/\r
}\r
\r
boolean isChar = props.getTextPropType() == TextPropType.character;\r
- \r
+\r
for (String pn : propNames) {\r
TextProp prop = master.getStyleAttribute(txtype, paragraph.getIndentLevel(), pn, isChar);\r
if (prop != null) return prop;\r
}\r
- \r
+\r
return null;\r
}\r
\r
*/\r
protected static void storeText(List<HSLFTextParagraph> paragraphs) {\r
fixLineEndings(paragraphs);\r
+ updateTextAtom(paragraphs);\r
+ updateStyles(paragraphs);\r
+ updateHyperlinks(paragraphs);\r
+ refreshRecords(paragraphs);\r
\r
- String rawText = toInternalString(getRawText(paragraphs));\r
+ for (HSLFTextParagraph p : paragraphs) {\r
+ p._dirty = false;\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Set the correct text atom depending on the multibyte usage\r
+ */\r
+ private static void updateTextAtom(List<HSLFTextParagraph> paragraphs) {\r
+ final String rawText = toInternalString(getRawText(paragraphs));\r
\r
// Will it fit in a 8 bit atom?\r
boolean isUnicode = StringUtil.hasMultibyte(rawText);\r
}\r
}\r
\r
+ }\r
+\r
+ /**\r
+ * Update paragraph and character styles - merges them when subsequential styles match\r
+ */\r
+ private static void updateStyles(List<HSLFTextParagraph> paragraphs) {\r
+ final String rawText = toInternalString(getRawText(paragraphs));\r
+ TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;\r
+ StyleTextPropAtom styleAtom = findStyleAtomPresent(headerAtom, rawText.length());\r
+\r
// Update the text length for its Paragraph and Character stylings\r
// * reset the length, to the new string's length\r
// * add on +1 if the last block\r
break;\r
}\r
}\r
+ }\r
\r
+ private static void updateHyperlinks(List<HSLFTextParagraph> paragraphs) {\r
+ TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;\r
+ RecordContainer _txtbox = headerAtom.getParentRecord();\r
+ // remove existing hyperlink records\r
+ for (Record r : _txtbox.getChildRecords()) {\r
+ if (r instanceof InteractiveInfo || r instanceof TxInteractiveInfoAtom) {\r
+ _txtbox.removeChild(r);\r
+ }\r
+ }\r
+ // now go through all the textruns and check for hyperlinks\r
+ HSLFHyperlink lastLink = null;\r
+ for (HSLFTextParagraph para : paragraphs) {\r
+ for (HSLFTextRun run : para) {\r
+ HSLFHyperlink thisLink = run.getHyperlink();\r
+ if (thisLink != null && thisLink == lastLink) {\r
+ // the hyperlink extends over this text run, increase its length\r
+ // TODO: the text run might be longer than the hyperlink\r
+ thisLink.setEndIndex(thisLink.getEndIndex()+run.getLength());\r
+ } else {\r
+ if (lastLink != null) {\r
+ InteractiveInfo info = lastLink.getInfo();\r
+ TxInteractiveInfoAtom txinfo = lastLink.getTextRunInfo();\r
+ assert(info != null && txinfo != null);\r
+ _txtbox.appendChildRecord(info);\r
+ _txtbox.appendChildRecord(txinfo);\r
+ }\r
+ }\r
+ lastLink = thisLink;\r
+ }\r
+ }\r
+\r
+ if (lastLink != null) {\r
+ InteractiveInfo info = lastLink.getInfo();\r
+ TxInteractiveInfoAtom txinfo = lastLink.getTextRunInfo();\r
+ assert(info != null && txinfo != null);\r
+ _txtbox.appendChildRecord(info);\r
+ _txtbox.appendChildRecord(txinfo);\r
+ } \r
+ }\r
+ \r
+ /**\r
+ * Writes the textbox records back to the document record \r
+ */\r
+ private static void refreshRecords(List<HSLFTextParagraph> paragraphs) {\r
+ TextHeaderAtom headerAtom = paragraphs.get(0)._headerAtom;\r
+ RecordContainer _txtbox = headerAtom.getParentRecord();\r
if (_txtbox instanceof EscherTextboxWrapper) {\r
try {\r
((EscherTextboxWrapper) _txtbox).writeOut(null);\r
throw new RuntimeException("failed dummy write", e);\r
}\r
}\r
-\r
- for (HSLFTextParagraph p : paragraphs) {\r
- p._dirty = false;\r
- }\r
}\r
\r
/**\r
}\r
return sb.toString();\r
}\r
- \r
+\r
@Override\r
public String toString() {\r
StringBuilder sb = new StringBuilder();\r
\r
protected static void applyHyperlinks(List<HSLFTextParagraph> paragraphs) {\r
List<HSLFHyperlink> links = HSLFHyperlink.find(paragraphs);\r
- \r
+\r
for (HSLFHyperlink h : links) {\r
int csIdx = 0;\r
for (HSLFTextParagraph p : paragraphs) {\r
- for (HSLFTextRun r : p) {\r
- if (h.getStartIndex() <= csIdx && csIdx < h.getEndIndex()) {\r
- r.setHyperlinkId(h.getId());\r
+ if (csIdx > h.getEndIndex()) break;\r
+ List<HSLFTextRun> runs = p.getTextRuns();\r
+ for (int rlen=0,rIdx=0; rIdx < runs.size(); csIdx+=rlen, rIdx++) {\r
+ HSLFTextRun run = runs.get(rIdx);\r
+ rlen = run.getLength();\r
+ if (csIdx < h.getEndIndex() && h.getStartIndex() < csIdx+rlen) {\r
+ String rawText = run.getRawText();\r
+ int startIdx = h.getStartIndex()-csIdx;\r
+ if (startIdx > 0) {\r
+ // hyperlink starts within current textrun\r
+ HSLFTextRun newRun = new HSLFTextRun(p);\r
+ newRun.setCharacterStyle(run.getCharacterStyle());\r
+ newRun.setText(rawText.substring(startIdx));\r
+ run.setText(rawText.substring(0, startIdx));\r
+ runs.add(rIdx+1, newRun);\r
+ rlen = startIdx;\r
+ continue;\r
+ }\r
+ int endIdx = Math.min(rlen, h.getEndIndex()-h.getStartIndex());\r
+ if (endIdx < rlen) {\r
+ // hyperlink ends before end of current textrun\r
+ HSLFTextRun newRun = new HSLFTextRun(p);\r
+ newRun.setCharacterStyle(run.getCharacterStyle());\r
+ newRun.setText(rawText.substring(0, endIdx));\r
+ run.setText(rawText.substring(endIdx));\r
+ runs.add(rIdx, newRun);\r
+ rlen = endIdx;\r
+ run = newRun;\r
+ }\r
+ run.setHyperlink(h);\r
}\r
- csIdx += r.getLength();\r
}\r
}\r
}\r
}\r
- \r
+\r
protected static void applyCharacterStyles(List<HSLFTextParagraph> paragraphs, List<TextPropCollection> charStyles) {\r
int paraIdx = 0, runIdx = 0;\r
HSLFTextRun trun;\r
public boolean isDirty() {\r
return _dirty;\r
}\r
- \r
+\r
/**\r
* Calculates the start index of the given text run\r
*\r
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;
private HSLFTextParagraph parentParagraph;
private String _runText = "";
private String _fontFamily;
- private int hyperlinkId = -1;
+ private HSLFHyperlink link;
/**
* Our paragraph and character style.
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
+ * Sets the hyperlink - used when parsing the document
*
- * @param hyperlinkId the id or -1 to unset it
+ * @param link the hyperlink
*/
- public void setHyperlinkId(int hyperlinkId) {
- this.hyperlinkId = hyperlinkId;
+ protected void setHyperlink(HSLFHyperlink link) {
+ this.link = link;
}
- /**
- * Returns the associated hyperlink id
- *
- * @return the hyperlink id
- */
- public int getHyperlinkId() {
- return hyperlinkId;
+ @Override
+ public HSLFHyperlink getHyperlink() {
+ return link;
}
-
@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;
+ public HSLFHyperlink createHyperlink() {
+ if (link == null) {
+ link = HSLFHyperlink.createHyperlink(this);
+ parentParagraph.setDirty();
}
-
- // 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;
}
}
import org.apache.poi.hslf.exceptions.HSLFException;
import org.apache.poi.hslf.model.HSLFMetroShape;
import org.apache.poi.hslf.record.EscherTextboxWrapper;
-import org.apache.poi.hslf.record.InteractiveInfo;
-import org.apache.poi.hslf.record.InteractiveInfoAtom;
import org.apache.poi.hslf.record.OEPlaceholderAtom;
import org.apache.poi.hslf.record.PPDrawing;
import org.apache.poi.hslf.record.RoundTripHFPlaceholder12;
import org.apache.poi.hslf.record.TextHeaderAtom;
-import org.apache.poi.hslf.record.TxInteractiveInfoAtom;
import org.apache.poi.sl.draw.DrawFactory;
import org.apache.poi.sl.draw.DrawTextShape;
import org.apache.poi.sl.usermodel.Insets2D;
return getClientDataRecord(RoundTripHFPlaceholder12.typeID);
}
- /**
- *
- * Assigns a hyperlink to this text shape
- *
- * @param linkId id of the hyperlink, @see org.apache.poi.hslf.usermodel.SlideShow#addHyperlink(Hyperlink)
- * @param beginIndex the beginning index, inclusive.
- * @param endIndex the ending index, exclusive.
- * @see org.apache.poi.hslf.usermodel.HSLFSlideShow#addHyperlink(HSLFHyperlink)
- */
- public void setHyperlink(int linkId, int beginIndex, int endIndex){
- //TODO validate beginIndex and endIndex and throw IllegalArgumentException
-
- InteractiveInfo info = new InteractiveInfo();
- InteractiveInfoAtom infoAtom = info.getInteractiveInfoAtom();
- infoAtom.setAction(org.apache.poi.hslf.record.InteractiveInfoAtom.ACTION_HYPERLINK);
- infoAtom.setHyperlinkType(org.apache.poi.hslf.record.InteractiveInfoAtom.LINK_Url);
- infoAtom.setHyperlinkID(linkId);
-
- _txtbox.appendChildRecord(info);
-
- TxInteractiveInfoAtom txiatom = new TxInteractiveInfoAtom();
- txiatom.setStartIndex(beginIndex);
- txiatom.setEndIndex(endIndex);
- _txtbox.appendChildRecord(txiatom);
-
- }
-
@Override
public boolean isPlaceholder() {
OEPlaceholderAtom oep = getPlaceholderAtom();
return HSLFTextParagraph.getRawText(getTextParagraphs());
}
- /**
- * Returns the text contained in this text frame, which has been made safe
- * for printing and other use.
- *
- * @return the text string for this textbox.
- */
+ @Override
public String getText() {
String rawText = getRawText();
return HSLFTextParagraph.toExternalString(rawText, getRunType());
}
+ @Override
+ public HSLFTextRun appendText(String text, boolean newParagraph) {
+ // init paragraphs
+ List<HSLFTextParagraph> paras = getTextParagraphs();
+ HSLFTextRun htr = HSLFTextParagraph.appendText(paras, text, newParagraph);
+ setTextId(getRawText().hashCode());
+ return htr;
+ }
- // Update methods follow
-
- /**
- * Adds the supplied text onto the end of the TextParagraphs,
- * creating a new RichTextRun for it to sit in.
- *
- * @param text the text string used by this object.
- */
- public HSLFTextRun appendText(String text, boolean newParagraph) {
- // init paragraphs
- List<HSLFTextParagraph> paras = getTextParagraphs();
- return HSLFTextParagraph.appendText(paras, text, newParagraph);
- }
-
- @Override
- public HSLFTextRun setText(String text) {
- // init paragraphs
- List<HSLFTextParagraph> paras = getTextParagraphs();
- HSLFTextRun htr = HSLFTextParagraph.setText(paras, text);
- setTextId(text.hashCode());
- return htr;
- }
-
- /**
- * Saves the modified paragraphs/textrun to the records.
- * Also updates the styles to the correct text length.
- */
- protected void storeText() {
- List<HSLFTextParagraph> paras = getTextParagraphs();
- HSLFTextParagraph.storeText(paras);
- }
- // Accesser methods follow
+ @Override
+ public HSLFTextRun setText(String text) {
+ // init paragraphs
+ List<HSLFTextParagraph> paras = getTextParagraphs();
+ HSLFTextRun htr = HSLFTextParagraph.setText(paras, text);
+ setTextId(getRawText().hashCode());
+ return htr;
+ }
+
+ /**
+ * Saves the modified paragraphs/textrun to the records.
+ * Also updates the styles to the correct text length.
+ */
+ protected void storeText() {
+ List<HSLFTextParagraph> paras = getTextParagraphs();
+ HSLFTextParagraph.storeText(paras);
+ }
/**
* Returns the array of all hyperlinks in this text run
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import org.apache.poi.POIDataSamples;
-import org.apache.poi.hslf.usermodel.*;
+import org.apache.poi.hslf.HSLFTestDataSamples;
+import org.apache.poi.hslf.record.InteractiveInfoAtom;
+import org.apache.poi.hslf.usermodel.HSLFHyperlink;
+import org.apache.poi.hslf.usermodel.HSLFSlide;
+import org.apache.poi.hslf.usermodel.HSLFSlideShow;
+import org.apache.poi.hslf.usermodel.HSLFTextBox;
+import org.apache.poi.hslf.usermodel.HSLFTextParagraph;
+import org.apache.poi.hslf.usermodel.HSLFTextRun;
+import org.apache.poi.sl.usermodel.Hyperlink;
import org.junit.Test;
/**
* Test Hyperlink.
- *
- * @author Yegor Kozlov
*/
public final class TestHyperlink {
private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
HSLFSlide slide = ppt.getSlides().get(0);
List<HSLFTextParagraph> para = slide.getTextParagraphs().get(1);
-
+
String rawText = toExternalString(getRawText(para), para.get(0).getRunType());
String expected =
"This page has two links:\n"+
"\n"+
"In addition, its notes has one link";
assertEquals(expected, rawText);
-
- List<HSLFHyperlink> links = HSLFHyperlink.find(para);
- assertNotNull(links);
+
+ List<HSLFHyperlink> links = findHyperlinks(para);
assertEquals(2, links.size());
assertEquals("http://jakarta.apache.org/poi/", links.get(0).getLabel());
slide = ppt.getSlides().get(1);
para = slide.getTextParagraphs().get(1);
rawText = toExternalString(getRawText(para), para.get(0).getRunType());
- expected =
+ expected =
"I have the one link:\n" +
"Jakarta HSSF";
assertEquals(expected, rawText);
- links = HSLFHyperlink.find(para);
+ links.clear();
+
+ links = findHyperlinks(para);
assertNotNull(links);
assertEquals(1, links.size());
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));
+
+ ppt.close();
+ }
+
+ @Test
+ public void bug47291() throws IOException {
+ HSLFSlideShow ppt1 = new HSLFSlideShow();
+ HSLFSlide slide1 = ppt1.createSlide();
+ HSLFTextRun r1 = slide1.createTextBox().setText("page1");
+ HSLFHyperlink hl1 = r1.createHyperlink();
+ hl1.linkToEmail("dev@poi.apache.org");
+ HSLFTextRun r2 = ppt1.createSlide().createTextBox().setText("page2");
+ HSLFHyperlink hl2 = r2.createHyperlink();
+ hl2.linkToLastSlide();
+ HSLFSlide sl1 = ppt1.createSlide();
+ HSLFTextBox tb1 = sl1.createTextBox();
+ tb1.setAnchor(new Rectangle2D.Double(100,100,100,100));
+ tb1.appendText("text1 ", false);
+ HSLFTextRun r3 = tb1.appendText("lin\u000bk", false);
+ tb1.appendText(" text2", false);
+ HSLFHyperlink hl3 = r3.createHyperlink();
+ hl3.linkToSlide(slide1);
+ HSLFTextRun r4 = ppt1.createSlide().createTextBox().setText("page4");
+ HSLFHyperlink hl4 = r4.createHyperlink();
+ hl4.linkToUrl("http://poi.apache.org");
+ HSLFTextBox tb5 = ppt1.createSlide().createTextBox();
+ tb5.setText("page5");
+ HSLFHyperlink hl5 = tb5.createHyperlink();
+ hl5.linkToFirstSlide();
+
+ HSLFSlideShow ppt2 = HSLFTestDataSamples.writeOutAndReadBack(ppt1);
+ ppt1.close();
+
+ List<HSLFSlide> slides = ppt2.getSlides();
+ tb1 = (HSLFTextBox)slides.get(0).getShapes().get(0);
+ hl1 = tb1.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
+ assertNotNull(hl1);
+ assertEquals("dev@poi.apache.org", hl1.getLabel());
+ assertEquals(Hyperlink.LINK_EMAIL, hl1.getType());
+
+ HSLFTextBox tb2 = (HSLFTextBox)slides.get(1).getShapes().get(0);
+ hl2 = tb2.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
+ assertNotNull(hl2);
+ assertEquals(InteractiveInfoAtom.LINK_LastSlide, hl2.getInfo().getInteractiveInfoAtom().getHyperlinkType());
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl2.getType());
+
+ HSLFTextBox tb3 = (HSLFTextBox)slides.get(2).getShapes().get(0);
+ hl3 = tb3.getTextParagraphs().get(0).getTextRuns().get(1).getHyperlink();
+ assertNotNull(hl3);
+ assertEquals(ppt2.getSlides().get(0)._getSheetNumber(), Integer.parseInt(hl3.getAddress().split(",")[0]));
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl3.getType());
+
+ HSLFTextBox tb4 = (HSLFTextBox)slides.get(3).getShapes().get(0);
+ hl4 = tb4.getTextParagraphs().get(0).getTextRuns().get(0).getHyperlink();
+ assertNotNull(hl4);
+ assertEquals("http://poi.apache.org", hl4.getLabel());
+ assertEquals(Hyperlink.LINK_URL, hl4.getType());
+
+ tb5 = (HSLFTextBox)slides.get(4).getShapes().get(0);
+ hl5 = tb5.getHyperlink();
+ assertNotNull(hl5);
+ assertEquals(InteractiveInfoAtom.LINK_FirstSlide, hl5.getInfo().getInteractiveInfoAtom().getHyperlinkType());
+ assertEquals(Hyperlink.LINK_DOCUMENT, hl5.getType());
+
+ ppt2.close();
+ }
+
+ private static List<HSLFHyperlink> findHyperlinks(List<HSLFTextParagraph> paras) {
+ List<HSLFHyperlink> links = new ArrayList<HSLFHyperlink>();
+ for (HSLFTextParagraph p : paras) {
+ for (HSLFTextRun r : p) {
+ HSLFHyperlink hl = r.getHyperlink();
+ if (hl != null) {
+ links.add(hl);
+ }
+ }
+ }
+ return links;
}
}
// Get the document
Document doc = ss.getDocumentRecord();
// Get the ExObjList
- ExObjList exObjList = doc.getExObjList();
+ ExObjList exObjList = doc.getExObjList(false);
assertNotNull(exObjList);
assertEquals(1033l, exObjList.getRecordType());