mirror of https://github.com/apache/poi.git
HSLF: readonly support for hyperlinks
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@542804 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5910a6c5b7
commit
8de5ebb35f
|
@ -38,6 +38,7 @@
|
||||||
<li><link href="#SlideTitle">How to set slide title</link></li>
|
<li><link href="#SlideTitle">How to set slide title</link></li>
|
||||||
<li><link href="#Fill">How to work with slide/shape background</link></li>
|
<li><link href="#Fill">How to work with slide/shape background</link></li>
|
||||||
<li><link href="#Bullets">How to create bulleted lists</link></li>
|
<li><link href="#Bullets">How to create bulleted lists</link></li>
|
||||||
|
<li><link href="#Hyperlinks">Hyperlinks</link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section><title>Features</title>
|
<section><title>Features</title>
|
||||||
|
@ -349,6 +350,43 @@
|
||||||
out.close();
|
out.close();
|
||||||
</source>
|
</source>
|
||||||
</section>
|
</section>
|
||||||
|
<anchor id="Hyperlinks"/>
|
||||||
|
<section><title>How to read hyperlinks from a slide show</title>
|
||||||
|
<source>
|
||||||
|
FileInputStream is = new FileInputStream("slideshow.ppt");
|
||||||
|
SlideShow ppt = new SlideShow(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
Slide[] slide = ppt.getSlides();
|
||||||
|
for (int j = 0; j < slide.length; j++) {
|
||||||
|
|
||||||
|
//read hyperlinks from the text runs
|
||||||
|
TextRun[] txt = slide[j].getTextRuns();
|
||||||
|
for (int k = 0; k < txt.length; k++) {
|
||||||
|
String text = txt[k].getText();
|
||||||
|
Hyperlink[] links = txt[k].getHyperlinks();
|
||||||
|
if(links != null) for (int l = 0; l < links.length; l++) {
|
||||||
|
Hyperlink link = links[l];
|
||||||
|
String title = link.getTitle();
|
||||||
|
String address = link.getAddress();
|
||||||
|
String substring = text.substring(link.getStartIndex(), link.getEndIndex()-1); //in ppt end index is inclusive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//in PowerPoint you can assign a hyperlink to a shape without text,
|
||||||
|
//for example to a Line object. The code below demonstrates how to
|
||||||
|
//read such hyperlinks
|
||||||
|
Shape[] sh = slide[j].getShapes();
|
||||||
|
for (int k = 0; k < sh.length; k++) {
|
||||||
|
Hyperlink link = sh[k].getHyperlink();
|
||||||
|
if(link != null) {
|
||||||
|
String title = link.getTitle();
|
||||||
|
String address = link.getAddress();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</source>
|
||||||
|
</section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.examples;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
import org.apache.poi.hslf.model.Slide;
|
||||||
|
import org.apache.poi.hslf.model.TextRun;
|
||||||
|
import org.apache.poi.hslf.model.Hyperlink;
|
||||||
|
import org.apache.poi.hslf.model.Shape;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrates how to read hyperlinks from a presentation
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class Hyperlinks {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
for (int i = 0; i < args.length; i++) {
|
||||||
|
FileInputStream is = new FileInputStream(args[i]);
|
||||||
|
SlideShow ppt = new SlideShow(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
Slide[] slide = ppt.getSlides();
|
||||||
|
for (int j = 0; j < slide.length; j++) {
|
||||||
|
System.out.println("slide " + slide[j].getSlideNumber());
|
||||||
|
|
||||||
|
//read hyperlinks from the slide's text runs
|
||||||
|
System.out.println("reading hyperlinks from the text runs");
|
||||||
|
TextRun[] txt = slide[j].getTextRuns();
|
||||||
|
for (int k = 0; k < txt.length; k++) {
|
||||||
|
String text = txt[k].getText();
|
||||||
|
Hyperlink[] links = txt[k].getHyperlinks();
|
||||||
|
if(links != null) for (int l = 0; l < links.length; l++) {
|
||||||
|
Hyperlink link = links[l];
|
||||||
|
String title = link.getTitle();
|
||||||
|
String address = link.getAddress();
|
||||||
|
System.out.println(" " + title);
|
||||||
|
System.out.println(" " + address);
|
||||||
|
String substring = text.substring(link.getStartIndex(), link.getEndIndex()-1);//in ppt end index is inclusive
|
||||||
|
System.out.println(" " + substring);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//in PowerPoint you can assign a hyperlink to a shape without text,
|
||||||
|
//for example to a Line object. The code below demonstrates how to
|
||||||
|
//read such hyperlinks
|
||||||
|
System.out.println(" reading hyperlinks from the slide's shapes");
|
||||||
|
Shape[] sh = slide[j].getShapes();
|
||||||
|
for (int k = 0; k < sh.length; k++) {
|
||||||
|
Hyperlink link = sh[k].getHyperlink();
|
||||||
|
if(link != null) {
|
||||||
|
String title = link.getTitle();
|
||||||
|
String address = link.getAddress();
|
||||||
|
System.out.println(" " + title);
|
||||||
|
System.out.println(" " + address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
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.model;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.record.*;
|
||||||
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherClientDataRecord;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a hyperlink in a PowerPoint document
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class Hyperlink {
|
||||||
|
|
||||||
|
private int type;
|
||||||
|
private String address;
|
||||||
|
private String title;
|
||||||
|
private int startIndex, endIndex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the type of the hyperlink action.
|
||||||
|
* Must be a <code>ACTION_*</code> constant defined in <code>InteractiveInfoAtom</code>
|
||||||
|
*
|
||||||
|
* @return the hyperlink URL
|
||||||
|
* @see InteractiveInfoAtom
|
||||||
|
*/
|
||||||
|
public int getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hyperlink URL
|
||||||
|
*
|
||||||
|
* @return the hyperlink URL
|
||||||
|
*/
|
||||||
|
public String getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the hyperlink user-friendly title (if different from URL)
|
||||||
|
*
|
||||||
|
* @return the hyperlink user-friendly title
|
||||||
|
*/
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the beginning character position
|
||||||
|
*
|
||||||
|
* @return the beginning character position
|
||||||
|
*/
|
||||||
|
public int getStartIndex() {
|
||||||
|
return startIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ending character position
|
||||||
|
*
|
||||||
|
* @return the ending character position
|
||||||
|
*/
|
||||||
|
public int getEndIndex() {
|
||||||
|
return endIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find hyperlinks in a text run
|
||||||
|
*
|
||||||
|
* @param run <code>TextRun</code> to lookup hyperlinks in
|
||||||
|
* @return found hyperlinks or <code>null</code> if not found
|
||||||
|
*/
|
||||||
|
protected static Hyperlink[] find(TextRun run){
|
||||||
|
ArrayList lst = new ArrayList();
|
||||||
|
SlideShow ppt = run.getSheet().getSlideShow();
|
||||||
|
//document-level container which stores info about all links in a presentation
|
||||||
|
ExObjList exobj = ppt.getDocumentRecord().getExObjList();
|
||||||
|
if (exobj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Record[] records = run._records;
|
||||||
|
if(records != null) find(records, exobj, lst);
|
||||||
|
|
||||||
|
Hyperlink[] links = null;
|
||||||
|
if (lst.size() > 0){
|
||||||
|
links = new Hyperlink[lst.size()];
|
||||||
|
lst.toArray(links);
|
||||||
|
}
|
||||||
|
return links;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find hyperlink assigned to the supplied shape
|
||||||
|
*
|
||||||
|
* @param shape <code>Shape</code> to lookup hyperlink in
|
||||||
|
* @return found hyperlink or <code>null</code>
|
||||||
|
*/
|
||||||
|
protected static Hyperlink find(Shape shape){
|
||||||
|
ArrayList lst = new ArrayList();
|
||||||
|
SlideShow ppt = shape.getSheet().getSlideShow();
|
||||||
|
//document-level container which stores info about all links in a presentation
|
||||||
|
ExObjList exobj = ppt.getDocumentRecord().getExObjList();
|
||||||
|
if (exobj == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
EscherContainerRecord spContainer = shape.getSpContainer();
|
||||||
|
List spchild = spContainer.getChildRecords();
|
||||||
|
for (Iterator it = spchild.iterator(); it.hasNext(); ) {
|
||||||
|
EscherRecord obj = (EscherRecord)it.next();
|
||||||
|
if (obj.getRecordId() == EscherClientDataRecord.RECORD_ID){
|
||||||
|
byte[] data = ((EscherContainerRecord)obj).serialize();
|
||||||
|
Record[] records = Record.findChildRecords(data, 8, data.length-8);
|
||||||
|
if(records != null) find(records, exobj, lst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lst.size() == 1 ? (Hyperlink)lst.get(0) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void find(Record[] records, ExObjList exobj, List out){
|
||||||
|
for (int i = 0; i < records.length; i++) {
|
||||||
|
//see if we have InteractiveInfo in the textrun's records
|
||||||
|
if( records[i] instanceof InteractiveInfo){
|
||||||
|
InteractiveInfo hldr = (InteractiveInfo)records[i];
|
||||||
|
InteractiveInfoAtom info = hldr.getInteractiveInfoAtom();
|
||||||
|
int id = info.getHyperlinkID();
|
||||||
|
ExHyperlink linkRecord = exobj.get(id);
|
||||||
|
if (linkRecord != null){
|
||||||
|
Hyperlink link = new Hyperlink();
|
||||||
|
link.title = linkRecord.getLinkTitle();
|
||||||
|
link.address = linkRecord.getLinkURL();
|
||||||
|
link.type = info.getAction();
|
||||||
|
|
||||||
|
if (++i < records.length && records[i] instanceof TxInteractiveInfoAtom){
|
||||||
|
TxInteractiveInfoAtom txinfo = (TxInteractiveInfoAtom)records[i];
|
||||||
|
link.startIndex = txinfo.getStartIndex();
|
||||||
|
link.endIndex = txinfo.getEndIndex();
|
||||||
|
}
|
||||||
|
out.add(link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -309,4 +309,15 @@ public abstract class Shape {
|
||||||
return new Fill(this);
|
return new Fill(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hyperlink assigned to this shape
|
||||||
|
*
|
||||||
|
* @return the hyperlink assigned to this shape
|
||||||
|
* or <code>null</code> if not found.
|
||||||
|
*/
|
||||||
|
public Hyperlink getHyperlink(){
|
||||||
|
return Hyperlink.find(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,4 +211,13 @@ public class ShapeGroup extends Shape{
|
||||||
return spRecord.getOptions() >> 4;
|
return spRecord.getOptions() >> 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns <code>null</code> - shape groups can't have hyperlinks
|
||||||
|
*
|
||||||
|
* @return <code>null</code>.
|
||||||
|
*/
|
||||||
|
public Hyperlink getHyperlink(){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.apache.poi.hslf.model;
|
||||||
import org.apache.poi.ddf.EscherContainerRecord;
|
import org.apache.poi.ddf.EscherContainerRecord;
|
||||||
import org.apache.poi.ddf.EscherDgRecord;
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
import org.apache.poi.ddf.EscherRecord;
|
import org.apache.poi.ddf.EscherRecord;
|
||||||
|
import org.apache.poi.ddf.EscherSpRecord;
|
||||||
import org.apache.poi.hslf.record.*;
|
import org.apache.poi.hslf.record.*;
|
||||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
|
||||||
|
@ -127,7 +128,13 @@ public abstract class Sheet {
|
||||||
Vector runsV = new Vector();
|
Vector runsV = new Vector();
|
||||||
EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
|
EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
|
||||||
for (int i = 0; i < wrappers.length; i++) {
|
for (int i = 0; i < wrappers.length; i++) {
|
||||||
|
int s1 = runsV.size();
|
||||||
findTextRuns(wrappers[i].getChildRecords(), runsV);
|
findTextRuns(wrappers[i].getChildRecords(), runsV);
|
||||||
|
int s2 = runsV.size();
|
||||||
|
if (s2 != s1){
|
||||||
|
TextRun t = (TextRun) runsV.get(runsV.size()-1);
|
||||||
|
t.setShapeId(wrappers[i].getShapeId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
TextRun[] runs = new TextRun[runsV.size()];
|
TextRun[] runs = new TextRun[runsV.size()];
|
||||||
for (int i = 0; i < runs.length; i++) {
|
for (int i = 0; i < runs.length; i++) {
|
||||||
|
@ -176,6 +183,15 @@ public abstract class Sheet {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (trun != null) {
|
if (trun != null) {
|
||||||
|
ArrayList lst = new ArrayList();
|
||||||
|
for (int j = i; j < records.length; j++) {
|
||||||
|
if(j > i && records[j] instanceof TextHeaderAtom) break;
|
||||||
|
lst.add(records[j]);
|
||||||
|
}
|
||||||
|
Record[] recs = new Record[lst.size()];
|
||||||
|
lst.toArray(recs);
|
||||||
|
trun._records = recs;
|
||||||
|
|
||||||
found.add(trun);
|
found.add(trun);
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
|
@ -232,6 +248,11 @@ public abstract class Sheet {
|
||||||
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
|
||||||
dg.setNumShapes(dg.getNumShapes() + 1);
|
dg.setNumShapes(dg.getNumShapes() + 1);
|
||||||
|
|
||||||
|
int shapeId = dg.getLastMSOSPID()+1;
|
||||||
|
dg.setLastMSOSPID(shapeId);
|
||||||
|
|
||||||
|
EscherSpRecord sp = shape.getSpContainer().getChildById(EscherSpRecord.RECORD_ID);
|
||||||
|
if(sp != null) sp.setShapeId(shapeId);
|
||||||
shape.setSheet(this);
|
shape.setSheet(this);
|
||||||
shape.afterInsert(this);
|
shape.afterInsert(this);
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,6 @@ import java.awt.*;
|
||||||
import java.awt.font.FontRenderContext;
|
import java.awt.font.FontRenderContext;
|
||||||
import java.awt.font.TextLayout;
|
import java.awt.font.TextLayout;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Vector;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a TextFrame shape in PowerPoint.
|
* Represents a TextFrame shape in PowerPoint.
|
||||||
|
@ -170,7 +169,7 @@ public class TextBox extends SimpleShape {
|
||||||
* @return the text string for this textbox.
|
* @return the text string for this textbox.
|
||||||
*/
|
*/
|
||||||
public String getText(){
|
public String getText(){
|
||||||
return _txtrun.getText();
|
return _txtrun == null ? null : _txtrun.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,56 +451,37 @@ public class TextBox extends SimpleShape {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initTextRun(){
|
private void initTextRun(){
|
||||||
TextHeaderAtom tha = null;
|
|
||||||
TextCharsAtom tca = null;
|
|
||||||
TextBytesAtom tba = null;
|
|
||||||
StyleTextPropAtom sta = null;
|
|
||||||
OutlineTextRefAtom ota = null;
|
OutlineTextRefAtom ota = null;
|
||||||
|
|
||||||
// Find the interesting child records
|
// Find the interesting child records
|
||||||
Record[] child = _txtbox.getChildRecords();
|
Record[] child = _txtbox.getChildRecords();
|
||||||
for (int i = 0; i < child.length; i++) {
|
for (int i = 0; i < child.length; i++) {
|
||||||
if (child[i] instanceof TextHeaderAtom) tha = (TextHeaderAtom)child[i];
|
if (child[i] instanceof OutlineTextRefAtom) {
|
||||||
else if (child[i] instanceof TextBytesAtom) tba = (TextBytesAtom)child[i];
|
ota = (OutlineTextRefAtom)child[i];
|
||||||
else if (child[i] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)child[i];
|
break;
|
||||||
else if (child[i] instanceof OutlineTextRefAtom) ota = (OutlineTextRefAtom)child[i];
|
}
|
||||||
else if (child[i] instanceof TextCharsAtom) tca = (TextCharsAtom)child[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special handling for cases where there's an OutlineTextRefAtom
|
Sheet sheet = getSheet();
|
||||||
|
TextRun[] runs = sheet.getTextRuns();
|
||||||
if (ota != null) {
|
if (ota != null) {
|
||||||
// TextHeaderAtom, TextBytesAtom and StyleTextPropAtom are
|
|
||||||
// stored outside of EscherContainerRecord
|
|
||||||
int idx = ota.getTextIndex();
|
int idx = ota.getTextIndex();
|
||||||
Slide sl = (Slide)getSheet();
|
if(idx < runs.length) _txtrun = runs[idx];
|
||||||
Record[] rec = sl.getSlideAtomsSet().getSlideRecords();
|
if(_txtrun == null) {
|
||||||
for (int i = 0, j = 0; i < rec.length; i++) {
|
logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx);
|
||||||
if(rec[i].getRecordType() == RecordTypes.TextHeaderAtom.typeID){
|
|
||||||
if(j++ == idx) { //we found j-th TextHeaderAtom, read the text data
|
|
||||||
for (int k = i; k < rec.length; k++) {
|
|
||||||
if (rec[k] instanceof TextHeaderAtom) {
|
|
||||||
if (tha != null) break;
|
|
||||||
else tha = (TextHeaderAtom)rec[k];
|
|
||||||
}
|
|
||||||
else if (rec[k] instanceof TextBytesAtom) tba = (TextBytesAtom)rec[k];
|
|
||||||
else if (rec[k] instanceof TextCharsAtom) tca = (TextCharsAtom)rec[k];
|
|
||||||
else if (rec[k] instanceof StyleTextPropAtom) sta = (StyleTextPropAtom)rec[k];
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
int shapeId = _escherContainer.getChildById(EscherSpRecord.RECORD_ID).getShapeId();
|
||||||
|
if(runs != null) for (int i = 0; i < runs.length; i++) {
|
||||||
|
if(runs[i].getShapeId() == shapeId){
|
||||||
|
_txtrun = runs[i];
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(_txtrun == null) {
|
||||||
|
logger.log(POILogger.WARN, "text run not found for shapeId=" + shapeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we found the records we needed, create a TextRun
|
|
||||||
if(tba != null) {
|
|
||||||
// Bytes based Text Run
|
|
||||||
_txtrun = new TextRun(tha,tba,sta);
|
|
||||||
} else if (tca != null) {
|
|
||||||
// Characters (unicode) based Text Run
|
|
||||||
_txtrun = new TextRun(tha,tca,sta);
|
|
||||||
} else {
|
|
||||||
// Empty text box
|
|
||||||
logger.log(POILogger.WARN, "no text records found for TextBox");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,12 @@ public class TextRun
|
||||||
protected RichTextRun[] _rtRuns;
|
protected RichTextRun[] _rtRuns;
|
||||||
private SlideShow slideShow;
|
private SlideShow slideShow;
|
||||||
private Sheet sheet;
|
private Sheet sheet;
|
||||||
|
private int shapeId;
|
||||||
|
/**
|
||||||
|
* all text run records that follow TextHeaderAtom.
|
||||||
|
* (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
|
||||||
|
*/
|
||||||
|
protected Record[] _records;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a Text Run from a Unicode text block
|
* Constructs a Text Run from a Unicode text block
|
||||||
|
@ -517,4 +523,28 @@ public class TextRun
|
||||||
public Sheet getSheet(){
|
public Sheet getSheet(){
|
||||||
return this.sheet;
|
return this.sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Shape ID
|
||||||
|
*/
|
||||||
|
protected int getShapeId(){
|
||||||
|
return shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id Shape ID
|
||||||
|
*/
|
||||||
|
protected void setShapeId(int id){
|
||||||
|
shapeId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the array of all hyperlinks in this text run
|
||||||
|
*
|
||||||
|
* @return the array of all hyperlinks in this text run
|
||||||
|
* or <code>null</code> if not found.
|
||||||
|
*/
|
||||||
|
public Hyperlink[] getHyperlinks(){
|
||||||
|
return Hyperlink.find(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class EscherTextboxWrapper extends RecordContainer
|
||||||
{
|
{
|
||||||
private EscherTextboxRecord _escherRecord;
|
private EscherTextboxRecord _escherRecord;
|
||||||
private long _type;
|
private long _type;
|
||||||
|
private int shapeId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the underlying DDF Escher Record
|
* Returns the underlying DDF Escher Record
|
||||||
|
@ -93,4 +94,18 @@ public class EscherTextboxWrapper extends RecordContainer
|
||||||
// Save in the escher layer
|
// Save in the escher layer
|
||||||
_escherRecord.setData(data);
|
_escherRecord.setData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Shape ID
|
||||||
|
*/
|
||||||
|
public int getShapeId(){
|
||||||
|
return shapeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id Shape ID
|
||||||
|
*/
|
||||||
|
public void setShapeId(int id){
|
||||||
|
shapeId = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,20 @@ public class ExHyperlink extends RecordContainer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the URL of the link.
|
* Returns the URL of the link.
|
||||||
* TODO: Figure out which of detailsA or detailsB is the
|
*
|
||||||
* one that always holds it
|
* @return the URL of the link
|
||||||
*/
|
*/
|
||||||
public String getLinkURL() {
|
public String getLinkURL() {
|
||||||
return linkDetailsA.getText();
|
return linkDetailsB == null ? null : linkDetailsB.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the hyperlink's user-readable name
|
||||||
|
*
|
||||||
|
* @return the hyperlink's user-readable name
|
||||||
|
*/
|
||||||
|
public String getLinkTitle() {
|
||||||
|
return linkDetailsA == null ? null : linkDetailsA.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -66,13 +75,13 @@ public class ExHyperlink extends RecordContainer {
|
||||||
* Get the link details (field A)
|
* Get the link details (field A)
|
||||||
*/
|
*/
|
||||||
public String _getDetailsA() {
|
public String _getDetailsA() {
|
||||||
return linkDetailsA.getText();
|
return linkDetailsA == null ? null : linkDetailsA.getText();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Get the link details (field B)
|
* Get the link details (field B)
|
||||||
*/
|
*/
|
||||||
public String _getDetailsB() {
|
public String _getDetailsB() {
|
||||||
return linkDetailsB.getText();
|
return linkDetailsB == null ? null : linkDetailsB.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -109,4 +109,21 @@ public class ExObjList extends RecordContainer {
|
||||||
writeOut(_header[0],_header[1],_type,_children,out);
|
writeOut(_header[0],_header[1],_type,_children,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lookup a hyperlink by its unique id
|
||||||
|
*
|
||||||
|
* @param id hyperlink id
|
||||||
|
* @return found <code>ExHyperlink</code> or <code>null</code>
|
||||||
|
*/
|
||||||
|
public ExHyperlink get(int id){
|
||||||
|
for(int i=0; i<_children.length; i++) {
|
||||||
|
if(_children[i] instanceof ExHyperlink) {
|
||||||
|
ExHyperlink rec = (ExHyperlink)_children[i];
|
||||||
|
if (rec.getExHyperlinkAtom().getNumber() == id){
|
||||||
|
return rec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,10 +30,37 @@ import org.apache.poi.util.LittleEndian;
|
||||||
* (The actual link is held Document.ExObjList.ExHyperlink)
|
* (The actual link is held Document.ExObjList.ExHyperlink)
|
||||||
*
|
*
|
||||||
* @author Nick Burch
|
* @author Nick Burch
|
||||||
|
* @author Yegor Kozlov
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class InteractiveInfoAtom extends RecordAtom
|
public class InteractiveInfoAtom extends RecordAtom
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action Table
|
||||||
|
*/
|
||||||
|
public static final int ACTION_NONE = 0;
|
||||||
|
public static final int ACTION_MACRO = 1;
|
||||||
|
public static final int ACTION_RUNPROGRAM = 2;
|
||||||
|
public static final int ACTION_JUMP = 3;
|
||||||
|
public static final int ACTION_HYPERLINK = 4;
|
||||||
|
public static final int ACTION_OLE = 5;
|
||||||
|
public static final int ACTION_MEDIA = 6;
|
||||||
|
public static final int ACTION_CUSTOMSHOW = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jump Table
|
||||||
|
*/
|
||||||
|
public static final int JUMP_NONE = 0;
|
||||||
|
public static final int JUMP_NEXTSLIDE = 1;
|
||||||
|
public static final int JUMP_PREVIOUSSLIDE = 2;
|
||||||
|
public static final int JUMP_FIRSTSLIDE = 3;
|
||||||
|
public static final int JUMP_LASTSLIDE = 4;
|
||||||
|
public static final int JUMP_LASTSLIDEVIEWED = 5;
|
||||||
|
public static final int JUMP_ENDSHOW = 6;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record header.
|
* Record header.
|
||||||
*/
|
*/
|
||||||
|
@ -90,46 +117,138 @@ public class InteractiveInfoAtom extends RecordAtom
|
||||||
* ExHyperlink with this number to get the details.
|
* ExHyperlink with this number to get the details.
|
||||||
* @return the link number
|
* @return the link number
|
||||||
*/
|
*/
|
||||||
public int getNumber() {
|
public int getHyperlinkID() {
|
||||||
return LittleEndian.getInt(_data,4);
|
return LittleEndian.getInt(_data,4);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the link number
|
* Sets the persistent unique identifier of the link
|
||||||
* @param number the link number.
|
*
|
||||||
|
* @param number the persistent unique identifier of the link
|
||||||
*/
|
*/
|
||||||
public void setNumber(int number) {
|
public void setHyperlinkID(int number) {
|
||||||
LittleEndian.putInt(_data,4,number);
|
LittleEndian.putInt(_data,4,number);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the first number - meaning unknown
|
* a reference to a sound in the sound collection.
|
||||||
*/
|
*/
|
||||||
public int _getNumber1() {
|
public int getSoundRef() {
|
||||||
return LittleEndian.getInt(_data,0);
|
return LittleEndian.getInt(_data,0);
|
||||||
}
|
}
|
||||||
protected void _setNumber1(int val) {
|
/**
|
||||||
|
* a reference to a sound in the sound collection.
|
||||||
|
*
|
||||||
|
* @param val a reference to a sound in the sound collection
|
||||||
|
*/
|
||||||
|
public void setSoundRef(int val) {
|
||||||
LittleEndian.putInt(_data, 0, val);
|
LittleEndian.putInt(_data, 0, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the third number - meaning unknown
|
* Hyperlink Action.
|
||||||
|
* <p>
|
||||||
|
* see <code>ACTION_*</code> constants for the list of actions
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return hyperlink action.
|
||||||
*/
|
*/
|
||||||
public int _getNumber3() {
|
public byte getAction() {
|
||||||
return LittleEndian.getInt(_data,8);
|
return _data[8];
|
||||||
}
|
|
||||||
protected void _setNumber3(int val) {
|
|
||||||
LittleEndian.putInt(_data, 8, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the fourth number - meaning unknown
|
* Hyperlink Action
|
||||||
|
* <p>
|
||||||
|
* see <code>ACTION_*</code> constants for the list of actions
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param val hyperlink action.
|
||||||
*/
|
*/
|
||||||
public int _getNumber4() {
|
public void setAction(byte val) {
|
||||||
return LittleEndian.getInt(_data,12);
|
_data[8] = val;
|
||||||
}
|
}
|
||||||
protected void _setNumber4(int val) {
|
|
||||||
LittleEndian.putInt(_data, 12, val);
|
/**
|
||||||
|
* Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
|
||||||
|
*/
|
||||||
|
public byte getOleVerb() {
|
||||||
|
return _data[9];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only valid when action == OLEAction. OLE verb to use, 0 = first verb, 1 = second verb, etc.
|
||||||
|
*/
|
||||||
|
public void setOleVerb(byte val) {
|
||||||
|
_data[9] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jump
|
||||||
|
* <p>
|
||||||
|
* see <code>JUMP_*</code> constants for the list of actions
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return jump
|
||||||
|
*/
|
||||||
|
public byte getJump() {
|
||||||
|
return _data[10];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Jump
|
||||||
|
* <p>
|
||||||
|
* see <code>JUMP_*</code> constants for the list of actions
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param val jump
|
||||||
|
*/
|
||||||
|
public void setJump(byte val) {
|
||||||
|
_data[10] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags
|
||||||
|
* <p>
|
||||||
|
* <li> Bit 1: Animated. If 1, then button is animated
|
||||||
|
* <li> Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
|
||||||
|
* <li> Bit 3: CustomShowReturn. If 1, and this is a jump to custom show,
|
||||||
|
* then return to this slide after custom show.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public byte getFlags() {
|
||||||
|
return _data[11];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags
|
||||||
|
* <p>
|
||||||
|
* <li> Bit 1: Animated. If 1, then button is animated
|
||||||
|
* <li> Bit 2: Stop sound. If 1, then stop current sound when button is pressed.
|
||||||
|
* <li> Bit 3: CustomShowReturn. If 1, and this is a jump to custom show,
|
||||||
|
* then return to this slide after custom show.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public void setFlags(byte val) {
|
||||||
|
_data[11] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hyperlink type
|
||||||
|
*
|
||||||
|
* @return hyperlink type
|
||||||
|
*/
|
||||||
|
public byte getHyperlinkType() {
|
||||||
|
return _data[12];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hyperlink type
|
||||||
|
*
|
||||||
|
* @param val hyperlink type
|
||||||
|
*/
|
||||||
|
public void setHyperlinkType(byte val) {
|
||||||
|
_data[12] = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -147,6 +147,13 @@ public class PPDrawing extends RecordAtom
|
||||||
EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i];
|
EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i];
|
||||||
EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
|
EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
|
||||||
found.add(w);
|
found.add(w);
|
||||||
|
for (int j = i; j >= 0; j--) {
|
||||||
|
if(toSearch[j] instanceof EscherSpRecord){
|
||||||
|
EscherSpRecord sp = (EscherSpRecord)toSearch[j];
|
||||||
|
w.setShapeId(sp.getShapeId());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// If it has children, walk them
|
// If it has children, walk them
|
||||||
if(toSearch[i].isContainerRecord()) {
|
if(toSearch[i].isContainerRecord()) {
|
||||||
|
|
|
@ -112,7 +112,7 @@ public class RecordTypes {
|
||||||
public static final Type SlideNumberMCAtom = new Type(4056,null);
|
public static final Type SlideNumberMCAtom = new Type(4056,null);
|
||||||
public static final Type HeadersFooters = new Type(4057,null);
|
public static final Type HeadersFooters = new Type(4057,null);
|
||||||
public static final Type HeadersFootersAtom = new Type(4058,null);
|
public static final Type HeadersFootersAtom = new Type(4058,null);
|
||||||
public static final Type TxInteractiveInfoAtom = new Type(4063,null);
|
public static final Type TxInteractiveInfoAtom = new Type(4063,TxInteractiveInfoAtom.class);
|
||||||
public static final Type CharFormatAtom = new Type(4066,null);
|
public static final Type CharFormatAtom = new Type(4066,null);
|
||||||
public static final Type ParaFormatAtom = new Type(4067,null);
|
public static final Type ParaFormatAtom = new Type(4067,null);
|
||||||
public static final Type RecolorInfoAtom = new Type(4071,null);
|
public static final Type RecolorInfoAtom = new Type(4071,null);
|
||||||
|
|
|
@ -0,0 +1,122 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.record;
|
||||||
|
|
||||||
|
import org.apache.poi.util.LittleEndian;
|
||||||
|
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tne atom that holds starting and ending character positions of a hyperlink
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TxInteractiveInfoAtom extends RecordAtom {
|
||||||
|
/**
|
||||||
|
* Record header.
|
||||||
|
*/
|
||||||
|
private byte[] _header;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record data.
|
||||||
|
*/
|
||||||
|
private byte[] _data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a brand new link related atom record.
|
||||||
|
*/
|
||||||
|
protected TxInteractiveInfoAtom() {
|
||||||
|
_header = new byte[8];
|
||||||
|
_data = new byte[8];
|
||||||
|
|
||||||
|
LittleEndian.putShort(_header, 2, (short)getRecordType());
|
||||||
|
LittleEndian.putInt(_header, 4, _data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the link related atom record from its
|
||||||
|
* source data.
|
||||||
|
*
|
||||||
|
* @param source the source data as a byte array.
|
||||||
|
* @param start the start offset into the byte array.
|
||||||
|
* @param len the length of the slice in the byte array.
|
||||||
|
*/
|
||||||
|
protected TxInteractiveInfoAtom(byte[] source, int start, int len) {
|
||||||
|
// Get the header.
|
||||||
|
_header = new byte[8];
|
||||||
|
System.arraycopy(source,start,_header,0,8);
|
||||||
|
|
||||||
|
// Get the record data.
|
||||||
|
_data = new byte[len-8];
|
||||||
|
System.arraycopy(source,start+8,_data,0,len-8);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the beginning character position
|
||||||
|
*
|
||||||
|
* @return the beginning character position
|
||||||
|
*/
|
||||||
|
public int getStartIndex() {
|
||||||
|
return LittleEndian.getInt(_data, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the beginning character position
|
||||||
|
* @param idx the beginning character position
|
||||||
|
*/
|
||||||
|
public void setStartIndex(int idx) {
|
||||||
|
LittleEndian.putInt(_data, 0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ending character position
|
||||||
|
*
|
||||||
|
* @return the ending character position
|
||||||
|
*/
|
||||||
|
public int getEndIndex() {
|
||||||
|
return LittleEndian.getInt(_data, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the ending character position
|
||||||
|
*
|
||||||
|
* @param idx the ending character position
|
||||||
|
*/
|
||||||
|
public void setEndIndex(int idx) {
|
||||||
|
LittleEndian.putInt(_data, 4, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the record type.
|
||||||
|
* @return the record type.
|
||||||
|
*/
|
||||||
|
public long getRecordType() { return RecordTypes.TxInteractiveInfoAtom.typeID; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the contents of the record back, so it can be written
|
||||||
|
* to disk
|
||||||
|
*
|
||||||
|
* @param out the output stream to write to.
|
||||||
|
* @throws java.io.IOException if an error occurs.
|
||||||
|
*/
|
||||||
|
public void writeOut(OutputStream out) throws IOException {
|
||||||
|
out.write(_header);
|
||||||
|
out.write(_data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* ====================================================================
|
||||||
|
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.model;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test Hyperlink.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestHyperlink extends TestCase {
|
||||||
|
protected String cwd = System.getProperty("HSLF.testdata.path");
|
||||||
|
|
||||||
|
public void testTextRunHyperlinks() throws Exception {
|
||||||
|
FileInputStream is = new FileInputStream(new File(cwd, "WithLinks.ppt"));
|
||||||
|
SlideShow ppt = new SlideShow(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
TextRun[] run;
|
||||||
|
Slide slide;
|
||||||
|
slide = ppt.getSlides()[0];
|
||||||
|
run = slide.getTextRuns();
|
||||||
|
for (int i = 0; i < run.length; i++) {
|
||||||
|
String text = run[i].getText();
|
||||||
|
if (text.equals(
|
||||||
|
"This page has two links:\n" +
|
||||||
|
"http://jakarta.apache.org/poi/\n" +
|
||||||
|
"\n" +
|
||||||
|
"http://slashdot.org/\n" +
|
||||||
|
"\n" +
|
||||||
|
"In addition, its notes has one link")){
|
||||||
|
|
||||||
|
Hyperlink[] links = run[i].getHyperlinks();
|
||||||
|
assertNotNull(links);
|
||||||
|
assertEquals(2, links.length);
|
||||||
|
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/", links[0].getTitle());
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/", links[0].getAddress());
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/", text.substring(links[0].getStartIndex(), links[0].getEndIndex()-1));
|
||||||
|
|
||||||
|
assertEquals("http://slashdot.org/", links[1].getTitle());
|
||||||
|
assertEquals("http://slashdot.org/", links[1].getAddress());
|
||||||
|
assertEquals("http://slashdot.org/", text.substring(links[1].getStartIndex(), links[1].getEndIndex()-1));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slide = ppt.getSlides()[1];
|
||||||
|
run = slide.getTextRuns();
|
||||||
|
for (int i = 0; i < run.length; i++) {
|
||||||
|
String text = run[i].getText();
|
||||||
|
if (text.equals(
|
||||||
|
"I have the one link:\n" +
|
||||||
|
"Jakarta HSSF")){
|
||||||
|
|
||||||
|
Hyperlink[] links = run[i].getHyperlinks();
|
||||||
|
assertNotNull(links);
|
||||||
|
assertEquals(1, links.length);
|
||||||
|
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getTitle());
|
||||||
|
assertEquals("http://jakarta.apache.org/poi/hssf/", links[0].getAddress());
|
||||||
|
assertEquals("Jakarta HSSF", text.substring(links[0].getStartIndex(), links[0].getEndIndex()-1));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -161,6 +161,7 @@ public class TestShapes extends TestCase {
|
||||||
out.close();
|
out.close();
|
||||||
|
|
||||||
ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));
|
ppt = new SlideShow(new HSLFSlideShow(new ByteArrayInputStream(out.toByteArray())));
|
||||||
|
sl = ppt.getSlides()[0];
|
||||||
|
|
||||||
txtbox = (TextBox)sl.getShapes()[0];
|
txtbox = (TextBox)sl.getShapes()[0];
|
||||||
rt = txtbox.getTextRun().getRichTextRuns()[0];
|
rt = txtbox.getTextRun().getRichTextRuns()[0];
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class TestInteractiveInfo extends TestCase {
|
||||||
InteractiveInfo ii = new InteractiveInfo(data_a, 0, data_a.length);
|
InteractiveInfo ii = new InteractiveInfo(data_a, 0, data_a.length);
|
||||||
InteractiveInfoAtom ia = ii.getInteractiveInfoAtom();
|
InteractiveInfoAtom ia = ii.getInteractiveInfoAtom();
|
||||||
|
|
||||||
assertEquals(1, ia.getNumber());
|
assertEquals(1, ia.getHyperlinkID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWrite() throws Exception {
|
public void testWrite() throws Exception {
|
||||||
|
@ -69,10 +69,10 @@ public class TestInteractiveInfo extends TestCase {
|
||||||
InteractiveInfoAtom ia = ii.getInteractiveInfoAtom();
|
InteractiveInfoAtom ia = ii.getInteractiveInfoAtom();
|
||||||
|
|
||||||
// Set values
|
// Set values
|
||||||
ia.setNumber(1);
|
ia.setHyperlinkID(1);
|
||||||
ia._setNumber1(0);
|
ia.setSoundRef(0);
|
||||||
ia._setNumber3(4);
|
ia.setAction((byte)4);
|
||||||
ia._setNumber4(8);
|
ia.setHyperlinkType((byte)8);
|
||||||
|
|
||||||
// Check it's now the same as a
|
// Check it's now the same as a
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
|
@ -53,22 +53,22 @@ public class TestInteractiveInfoAtom extends TestCase {
|
||||||
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
|
InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
|
||||||
|
|
||||||
assertEquals(1, ia.getNumber());
|
assertEquals(1, ia.getHyperlinkID());
|
||||||
assertEquals(4, ib.getNumber());
|
assertEquals(4, ib.getHyperlinkID());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testGetRest() throws Exception {
|
public void testGetRest() throws Exception {
|
||||||
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
|
InteractiveInfoAtom ib = new InteractiveInfoAtom(data_b, 0, data_b.length);
|
||||||
|
|
||||||
assertEquals(0, ia._getNumber1());
|
assertEquals(0, ia.getSoundRef());
|
||||||
assertEquals(0, ib._getNumber1());
|
assertEquals(0, ib.getSoundRef());
|
||||||
|
|
||||||
assertEquals(4, ia._getNumber3());
|
assertEquals(4, ia.getAction());
|
||||||
assertEquals(4, ib._getNumber3());
|
assertEquals(4, ib.getAction());
|
||||||
|
|
||||||
assertEquals(8, ia._getNumber4());
|
assertEquals(8, ia.getHyperlinkType());
|
||||||
assertEquals(8, ib._getNumber4());
|
assertEquals(8, ib.getHyperlinkType());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testWrite() throws Exception {
|
public void testWrite() throws Exception {
|
||||||
|
@ -88,10 +88,10 @@ public class TestInteractiveInfoAtom extends TestCase {
|
||||||
InteractiveInfoAtom ia = new InteractiveInfoAtom();
|
InteractiveInfoAtom ia = new InteractiveInfoAtom();
|
||||||
|
|
||||||
// Set values
|
// Set values
|
||||||
ia.setNumber(1);
|
ia.setHyperlinkID(1);
|
||||||
ia._setNumber1(0);
|
ia.setSoundRef(0);
|
||||||
ia._setNumber3(4);
|
ia.setAction((byte)4);
|
||||||
ia._setNumber4(8);
|
ia.setHyperlinkType((byte)8);
|
||||||
|
|
||||||
// Check it's now the same as a
|
// Check it's now the same as a
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
@ -109,7 +109,7 @@ public class TestInteractiveInfoAtom extends TestCase {
|
||||||
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
InteractiveInfoAtom ia = new InteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
|
|
||||||
// Change the number
|
// Change the number
|
||||||
ia.setNumber(4);
|
ia.setHyperlinkID(4);
|
||||||
|
|
||||||
// Check bytes are now the same
|
// Check bytes are now the same
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
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.record;
|
||||||
|
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that TxInteractiveInfoAtom works properly.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestTxInteractiveInfoAtom extends TestCase {
|
||||||
|
// From WithLinks.ppt
|
||||||
|
private byte[] data_a = new byte[] {
|
||||||
|
00, 00, (byte)0xDF, 0x0F, 0x08, 00, 00, 00,
|
||||||
|
0x19, 00, 00, 00, 0x38, 00, 00, 00
|
||||||
|
};
|
||||||
|
|
||||||
|
private byte[] data_b = new byte[] {
|
||||||
|
00, 00, (byte)0xDF, 0x0F, 0x08, 00, 00, 00,
|
||||||
|
0x39, 00, 00, 00, 0x4E, 00, 00, 00
|
||||||
|
};
|
||||||
|
|
||||||
|
public void testRead() throws Exception {
|
||||||
|
TxInteractiveInfoAtom ia1 = new TxInteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
|
|
||||||
|
assertEquals(4063, ia1.getRecordType());
|
||||||
|
assertEquals(25, ia1.getStartIndex());
|
||||||
|
assertEquals(56, ia1.getEndIndex());
|
||||||
|
|
||||||
|
TxInteractiveInfoAtom ia2 = new TxInteractiveInfoAtom(data_b, 0, data_b.length);
|
||||||
|
|
||||||
|
assertEquals(4063, ia2.getRecordType());
|
||||||
|
assertEquals(57, ia2.getStartIndex());
|
||||||
|
assertEquals(78, ia2.getEndIndex());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testWrite() throws Exception {
|
||||||
|
TxInteractiveInfoAtom atom = new TxInteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
atom.writeOut(baos);
|
||||||
|
byte[] b = baos.toByteArray();
|
||||||
|
|
||||||
|
assertEquals(data_a.length, b.length);
|
||||||
|
for(int i=0; i<data_a.length; i++) {
|
||||||
|
assertEquals(data_a[i],b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create A from scratch
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
TxInteractiveInfoAtom ia = new TxInteractiveInfoAtom();
|
||||||
|
|
||||||
|
// Set values
|
||||||
|
ia.setStartIndex(25);
|
||||||
|
ia.setEndIndex(56);
|
||||||
|
|
||||||
|
// Check it's now the same as a
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ia.writeOut(baos);
|
||||||
|
byte[] b = baos.toByteArray();
|
||||||
|
|
||||||
|
assertEquals(data_a.length, b.length);
|
||||||
|
for(int i=0; i<data_a.length; i++) {
|
||||||
|
assertEquals(data_a[i],b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to turn a into b
|
||||||
|
public void testChange() throws Exception {
|
||||||
|
TxInteractiveInfoAtom ia = new TxInteractiveInfoAtom(data_a, 0, data_a.length);
|
||||||
|
|
||||||
|
// Change the number
|
||||||
|
ia.setStartIndex(57);
|
||||||
|
ia.setEndIndex(78);
|
||||||
|
|
||||||
|
// Check bytes are now the same
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
ia.writeOut(baos);
|
||||||
|
byte[] b = baos.toByteArray();
|
||||||
|
|
||||||
|
// Should now be the same
|
||||||
|
assertEquals(data_b.length, b.length);
|
||||||
|
for(int i=0; i<data_b.length; i++) {
|
||||||
|
assertEquals(data_b[i],b[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue