git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1724338 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_14_FINAL
@@ -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 |
@@ -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); | |||
} | |||
} |
@@ -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) | |||
*/ |
@@ -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(); | |||
} |
@@ -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 = |
@@ -449,6 +449,7 @@ public class XSLFTextRun implements TextRun { | |||
return link; | |||
} | |||
@Override | |||
public XSLFHyperlink getHyperlink(){ | |||
if(!_r.getRPr().isSetHlinkClick()) return null; | |||
@@ -282,7 +282,7 @@ public final class PPGraphics2D extends Graphics2D implements Cloneable { | |||
*/ | |||
public void drawString(String s, float x, float y) { | |||
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); |
@@ -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; | |||
} | |||
/** | |||
@@ -139,6 +133,15 @@ public final class HSLFHyperlink { | |||
return startIndex; | |||
} | |||
/** | |||
* Sets the beginning character position | |||
* | |||
* @param startIndex the beginning character position | |||
*/ | |||
public void setStartIndex(int startIndex) { | |||
this.startIndex = startIndex; | |||
} | |||
/** | |||
* Gets the ending character position | |||
* | |||
@@ -148,6 +151,15 @@ public final class HSLFHyperlink { | |||
return endIndex; | |||
} | |||
/** | |||
* Sets the ending character position | |||
* | |||
* @param endIndex the ending character position | |||
*/ | |||
public void setEndIndex(int endIndex) { | |||
this.endIndex = endIndex; | |||
} | |||
/** | |||
* Find hyperlinks in a text shape | |||
* | |||
@@ -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()); | |||
} | |||
} | |||
} |
@@ -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); | |||
} | |||
} | |||
} | |||
/** |
@@ -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); | |||
} | |||
} | |||
@@ -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; | |||
} | |||
@@ -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); | |||
} | |||
} | |||
} | |||
/** |
@@ -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); | |||
} | |||
} | |||
} | |||
/** |
@@ -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); |
@@ -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; | |||
} | |||
} |
@@ -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; | |||
} | |||
} |
@@ -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); | |||
} | |||
/** |
@@ -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)); | |||
} |
@@ -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); |