| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.hslf.usermodel; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.ListIterator; |
| |
| import org.apache.poi.common.usermodel.HyperlinkType; |
| 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.InteractiveInfoAtom; |
| 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<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 HSLFSimpleShape#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. |
| * Must be a <code>LINK_*</code> constant</code> |
| * |
| * @return the hyperlink URL |
| * @see InteractiveInfoAtom |
| * @deprecated POI 3.15 beta 3. Use {@link #getTypeEnum()} |
| */ |
| @Override |
| public int getType() { |
| return getTypeEnum().getCode(); |
| } |
| |
| /** |
| * Gets the type of the hyperlink action. |
| * Must be a <code>LINK_*</code> constant</code> |
| * |
| * @return the hyperlink URL |
| * @see InteractiveInfoAtom |
| */ |
| @Override |
| public HyperlinkType getTypeEnum() { |
| switch (info.getInteractiveInfoAtom().getHyperlinkType()) { |
| case InteractiveInfoAtom.LINK_Url: |
| return (exHyper.getLinkURL().startsWith("mailto:")) ? HyperlinkType.EMAIL : HyperlinkType.URL; |
| case InteractiveInfoAtom.LINK_NextSlide: |
| case InteractiveInfoAtom.LINK_PreviousSlide: |
| case InteractiveInfoAtom.LINK_FirstSlide: |
| case InteractiveInfoAtom.LINK_LastSlide: |
| case InteractiveInfoAtom.LINK_SlideNumber: |
| return HyperlinkType.DOCUMENT; |
| case InteractiveInfoAtom.LINK_CustomShow: |
| case InteractiveInfoAtom.LINK_OtherPresentation: |
| case InteractiveInfoAtom.LINK_OtherFile: |
| return HyperlinkType.FILE; |
| default: |
| case InteractiveInfoAtom.LINK_NULL: |
| return HyperlinkType.NONE; |
| } |
| } |
| |
| @Override |
| 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); |
| } |
| |
| @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 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); |
| } |
| |
| @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); |
| } |
| |
| @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 exHyper.getLinkTitle(); |
| } |
| |
| @Override |
| public void setLabel(String label) { |
| exHyper.setLinkTitle(label); |
| } |
| |
| /** |
| * Gets the beginning character position |
| * |
| * @return the beginning character position |
| */ |
| public int getStartIndex() { |
| return (txinfo == null) ? -1 : txinfo.getStartIndex(); |
| } |
| |
| /** |
| * Sets the beginning character position |
| * |
| * @param startIndex the beginning character position |
| */ |
| public void setStartIndex(int startIndex) { |
| if (txinfo != null) { |
| txinfo.setStartIndex(startIndex); |
| } |
| } |
| |
| /** |
| * Gets the ending character position |
| * |
| * @return the ending character position |
| */ |
| public int getEndIndex() { |
| return (txinfo == null) ? -1 : txinfo.getEndIndex(); |
| } |
| |
| /** |
| * Sets the ending character position |
| * |
| * @param endIndex the ending character position |
| */ |
| public void setEndIndex(int endIndex) { |
| if (txinfo != null) { |
| txinfo.setEndIndex(endIndex); |
| } |
| } |
| |
| /** |
| * Find hyperlinks in a text shape |
| * |
| * @param shape <code>TextRun</code> to lookup hyperlinks in |
| * @return found hyperlinks or <code>null</code> if not found |
| */ |
| public static List<HSLFHyperlink> find(HSLFTextShape shape){ |
| return find(shape.getTextParagraphs()); |
| } |
| |
| /** |
| * Find hyperlinks in a text paragraph |
| * |
| * @param paragraphs List of <code>TextParagraph</code> to lookup hyperlinks |
| * @return found hyperlinks |
| */ |
| @SuppressWarnings("resource") |
| 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(false); |
| if (exobj != null) { |
| Record[] records = firstPara.getRecords(); |
| find(Arrays.asList(records), exobj, lst); |
| } |
| |
| return lst; |
| } |
| |
| /** |
| * Find hyperlink assigned to the supplied shape |
| * |
| * @param shape <code>Shape</code> to lookup hyperlink in |
| * @return found hyperlink or <code>null</code> |
| */ |
| @SuppressWarnings("resource") |
| 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(false); |
| HSLFEscherClientDataRecord cldata = shape.getClientData(false); |
| |
| if (exobj != null && cldata != null) { |
| List<HSLFHyperlink> lst = new ArrayList<HSLFHyperlink>(); |
| find(cldata.getHSLFChildRecords(), exobj, lst); |
| return lst.isEmpty() ? null : (HSLFHyperlink)lst.get(0); |
| } |
| |
| return null; |
| } |
| |
| private static void find(List<? extends Record> records, ExObjList exobj, List<HSLFHyperlink> out){ |
| ListIterator<? extends Record> iter = records.listIterator(); |
| while (iter.hasNext()) { |
| Record r = iter.next(); |
| // see if we have InteractiveInfo in the textrun's records |
| if (!(r instanceof InteractiveInfo)) { |
| continue; |
| } |
| |
| InteractiveInfo hldr = (InteractiveInfo)r; |
| InteractiveInfoAtom info = hldr.getInteractiveInfoAtom(); |
| if (info == null) { |
| continue; |
| } |
| int id = info.getHyperlinkID(); |
| ExHyperlink exHyper = exobj.get(id); |
| if (exHyper == null) { |
| continue; |
| } |
| |
| HSLFHyperlink link = new HSLFHyperlink(exHyper, hldr); |
| out.add(link); |
| |
| if (iter.hasNext()) { |
| r = iter.next(); |
| if (!(r instanceof TxInteractiveInfoAtom)) { |
| iter.previous(); |
| continue; |
| } |
| link.setTextRunInfo((TxInteractiveInfoAtom)r); |
| } |
| } |
| } |
| } |