support for excel hypelrinks
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@619310 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
142936990c
commit
ab1c14b324
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
<!-- Don't forget to update status.xml too! -->
|
<!-- Don't forget to update status.xml too! -->
|
||||||
<release version="3.1-beta1" date="2008-??-??">
|
<release version="3.1-beta1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">37923 - Support for Excel hyperlinks</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Implement hashCode() and equals(obj) on HSSFFont and HSSFCellStyle</action>
|
<action dev="POI-DEVELOPERS" type="add">Implement hashCode() and equals(obj) on HSSFFont and HSSFCellStyle</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
|
<action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
|
<action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
<li><link href="#NamedRanges">Named Ranges and Named Cells</link></li>
|
<li><link href="#NamedRanges">Named Ranges and Named Cells</link></li>
|
||||||
<li><link href="#CellComments">How to set cell comments</link></li>
|
<li><link href="#CellComments">How to set cell comments</link></li>
|
||||||
<li><link href="#Autofit">How to adjust column width to fit the contents</link></li>
|
<li><link href="#Autofit">How to adjust column width to fit the contents</link></li>
|
||||||
|
<li><link href="#Hyperlinks">Hyperlinks</link></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section><title>Features</title>
|
<section><title>Features</title>
|
||||||
@ -1322,6 +1323,76 @@ Examples:
|
|||||||
(either via <code>-Djava.awt.headless=true</code> startup parameter or via <code>System.setProperty("java.awt.headless", "true")</code>).
|
(either via <code>-Djava.awt.headless=true</code> startup parameter or via <code>System.setProperty("java.awt.headless", "true")</code>).
|
||||||
</warning>
|
</warning>
|
||||||
</section>
|
</section>
|
||||||
|
<anchor id="Hyperlinks"/>
|
||||||
|
<section><title>How to read hyperlinks</title>
|
||||||
|
<source>
|
||||||
|
HSSFSheet sheet = workbook.getSheetAt(0);
|
||||||
|
|
||||||
|
HSSFCell cell = sheet.getRow(0).getCell((short)0);
|
||||||
|
HSSFHyperlink link = cell.getHyperlink();
|
||||||
|
if(link != null){
|
||||||
|
System.out.println(link.getAddress());
|
||||||
|
}
|
||||||
|
</source>
|
||||||
|
</section>
|
||||||
|
<section><title>How to create hyperlinks</title>
|
||||||
|
<source>
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
//cell style for hyperlinks
|
||||||
|
//by default hypelrinks are blue and underlined
|
||||||
|
HSSFCellStyle hlink_style = wb.createCellStyle();
|
||||||
|
HSSFFont hlink_font = wb.createFont();
|
||||||
|
hlink_font.setUnderline(HSSFFont.U_SINGLE);
|
||||||
|
hlink_font.setColor(HSSFColor.BLUE.index);
|
||||||
|
hlink_style.setFont(hlink_font);
|
||||||
|
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFSheet sheet = wb.createSheet("Hyperlinks");
|
||||||
|
|
||||||
|
//URL
|
||||||
|
cell = sheet.createRow(0).createCell((short)0);
|
||||||
|
cell.setCellValue("URL Link");
|
||||||
|
HSSFHyperlink link = new HSSFHyperlink(HSSFHyperlink.LINK_URL);
|
||||||
|
link.setAddress("http://poi.apache.org/");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//link to a file in the current directory
|
||||||
|
cell = sheet.createRow(1).createCell((short)0);
|
||||||
|
cell.setCellValue("File Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_FILE);
|
||||||
|
link.setAddress("link1.xls");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//e-mail link
|
||||||
|
cell = sheet.createRow(2).createCell((short)0);
|
||||||
|
cell.setCellValue("Email Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_EMAIL);
|
||||||
|
//note, if subject contains white spaces, make sure they are url-encoded
|
||||||
|
link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//link to a place in this workbook
|
||||||
|
|
||||||
|
//create a target sheet and cell
|
||||||
|
HSSFSheet sheet2 = wb.createSheet("Target Sheet");
|
||||||
|
sheet2.createRow(0).createCell((short)0).setCellValue("Target Cell");
|
||||||
|
|
||||||
|
cell = sheet.createRow(3).createCell((short)0);
|
||||||
|
cell.setCellValue("Worksheet Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_DOCUMENT);
|
||||||
|
link.setAddress("'Target Sheet'!A1");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
FileOutputStream out = new FileOutputStream("hssf-links.xls");
|
||||||
|
wb.write(out);
|
||||||
|
out.close();
|
||||||
|
</source>
|
||||||
|
</section>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</document>
|
</document>
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
<!-- Don't forget to update changes.xml too! -->
|
<!-- Don't forget to update changes.xml too! -->
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.1-beta1" date="2008-??-??">
|
<release version="3.1-beta1" date="2008-??-??">
|
||||||
|
<action dev="POI-DEVELOPERS" type="add">37923 - Support for Excel hyperlinks</action>
|
||||||
<action dev="POI-DEVELOPERS" type="add">Implement hashCode() and equals(obj) on HSSFFont and HSSFCellStyle</action>
|
<action dev="POI-DEVELOPERS" type="add">Implement hashCode() and equals(obj) on HSSFFont and HSSFCellStyle</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
|
<action dev="POI-DEVELOPERS" type="fix">44345 - Implement CountA, CountIf, Index, Rows and Columns functions</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
|
<action dev="POI-DEVELOPERS" type="fix">44336 - Properly escape sheet names as required when figuring out the text of formulas</action>
|
||||||
|
91
src/examples/src/org/apache/poi/hssf/usermodel/examples/Hyperlinks.java
Executable file
91
src/examples/src/org/apache/poi/hssf/usermodel/examples/Hyperlinks.java
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
/* ====================================================================
|
||||||
|
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.hssf.usermodel.examples;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.usermodel.*;
|
||||||
|
import org.apache.poi.hssf.util.HSSFColor;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Demonstrates how to create hyperlinks.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov (yegor at apach.org)
|
||||||
|
*/
|
||||||
|
public class Hyperlinks {
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
//cell style for hyperlinks
|
||||||
|
//by default hypelrinks are blue and underlined
|
||||||
|
HSSFCellStyle hlink_style = wb.createCellStyle();
|
||||||
|
HSSFFont hlink_font = wb.createFont();
|
||||||
|
hlink_font.setUnderline(HSSFFont.U_SINGLE);
|
||||||
|
hlink_font.setColor(HSSFColor.BLUE.index);
|
||||||
|
hlink_style.setFont(hlink_font);
|
||||||
|
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFSheet sheet = wb.createSheet("Hyperlinks");
|
||||||
|
|
||||||
|
//URL
|
||||||
|
cell = sheet.createRow(0).createCell((short)0);
|
||||||
|
cell.setCellValue("URL Link");
|
||||||
|
HSSFHyperlink link = new HSSFHyperlink(HSSFHyperlink.LINK_URL);
|
||||||
|
link.setAddress("http://poi.apache.org/");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//link to a file in the current directory
|
||||||
|
cell = sheet.createRow(1).createCell((short)0);
|
||||||
|
cell.setCellValue("File Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_FILE);
|
||||||
|
link.setAddress("link1.xls");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//e-mail link
|
||||||
|
cell = sheet.createRow(2).createCell((short)0);
|
||||||
|
cell.setCellValue("Email Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_EMAIL);
|
||||||
|
//note, if subject contains white spaces, make sure they are url-encoded
|
||||||
|
link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
//link to a place in this workbook
|
||||||
|
|
||||||
|
//create a target sheet and cell
|
||||||
|
HSSFSheet sheet2 = wb.createSheet("Target Sheet");
|
||||||
|
sheet2.createRow(0).createCell((short)0).setCellValue("Target Cell");
|
||||||
|
|
||||||
|
cell = sheet.createRow(3).createCell((short)0);
|
||||||
|
cell.setCellValue("Worksheet Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_DOCUMENT);
|
||||||
|
link.setAddress("'Target Sheet'!A1");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
cell.setCellStyle(hlink_style);
|
||||||
|
|
||||||
|
FileOutputStream out = new FileOutputStream("hssf-links.xls");
|
||||||
|
wb.write(out);
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,29 +1,27 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
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
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
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,
|
||||||
Unless required by applicable law or agreed to in writing, software
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
See the License for the specific language governing permissions and
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
limitations under the License.
|
||||||
See the License for the specific language governing permissions and
|
==================================================================== */
|
||||||
limitations under the License.
|
|
||||||
==================================================================== */
|
|
||||||
|
|
||||||
package org.apache.poi.hssf.record;
|
package org.apache.poi.hssf.record;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.util.Arrays;
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
|
||||||
import org.apache.commons.logging.LogFactory;
|
|
||||||
import org.apache.poi.util.LittleEndian;
|
import org.apache.poi.util.LittleEndian;
|
||||||
import org.apache.poi.util.StringUtil;
|
import org.apache.poi.util.StringUtil;
|
||||||
|
import org.apache.poi.util.HexDump;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The <code>HyperlinkRecord</code> wraps an HLINK-record
|
* The <code>HyperlinkRecord</code> wraps an HLINK-record
|
||||||
@ -31,146 +29,283 @@ import org.apache.poi.util.StringUtil;
|
|||||||
* Supports only external links for now (eg http://)
|
* Supports only external links for now (eg http://)
|
||||||
*
|
*
|
||||||
* @author Mark Hissink Muller <a href="mailto:mark@hissinkmuller.nl >mark&064;hissinkmuller.nl</a>
|
* @author Mark Hissink Muller <a href="mailto:mark@hissinkmuller.nl >mark&064;hissinkmuller.nl</a>
|
||||||
|
* @author Yegor Kozlov (yegor at apache dot org)
|
||||||
*/
|
*/
|
||||||
public class HyperlinkRecord extends Record implements CellValueRecordInterface
|
public class HyperlinkRecord extends Record {
|
||||||
{
|
/**
|
||||||
/** Indicates the URL in the Record */
|
* Link flags
|
||||||
private static byte[] GUID_OF_URL_MONIKER =
|
*/
|
||||||
{ -32, -55, -22, 121, -7, -70, -50, 17, -116, -126, 0, -86, 0, 75, -87, 11 };
|
protected static final int HLINK_URL = 0x01; // File link or URL.
|
||||||
|
protected static final int HLINK_ABS = 0x02; // Absolute path.
|
||||||
|
protected static final int HLINK_LABEL = 0x14; // Has label.
|
||||||
|
protected static final int HLINK_PLACE = 0x08; // Place in worksheet.
|
||||||
|
|
||||||
/** Indicates the STD_LINK in the Record */
|
|
||||||
// MHM: to be added when necessary
|
|
||||||
private static byte[] GUID_OF_STD_LINK = {};
|
|
||||||
|
|
||||||
/** Logger */
|
protected final static byte[] STD_MONIKER = {(byte)0xD0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
public static final Log log = LogFactory.getLog(HyperlinkRecord.class);
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B };
|
||||||
|
protected final static byte[] URL_MONIKER = {(byte)0xE0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B };
|
||||||
|
protected final static byte[] FILE_MONIKER = {0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46};
|
||||||
|
|
||||||
// quick and dirty
|
/**
|
||||||
private static final boolean _DEBUG_ = true;
|
* Tail of a URL link
|
||||||
|
*/
|
||||||
|
protected final static byte[] URL_TAIL = {0x79, 0x58, (byte)0x81, (byte)0xF4, 0x3B, 0x1D, 0x7F, 0x48, (byte)0xAF, 0x2C,
|
||||||
|
(byte)0x82, 0x5D, (byte)0xC4, (byte)0x85, 0x27, 0x63, 0x00, 0x00, 0x00,
|
||||||
|
0x00, (byte)0xA5, (byte)0xAB, 0x00, 0x00};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tail of a file link
|
||||||
|
*/
|
||||||
|
protected final static byte[] FILE_TAIL = {(byte)0xFF, (byte)0xFF, (byte)0xAD, (byte)0xDE, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
public final static short sid = 0x1b8;
|
public final static short sid = 0x1b8;
|
||||||
|
|
||||||
private short field_1_unknown;
|
/**
|
||||||
private int field_2_row;
|
* First row of the hyperlink
|
||||||
private short field_3_column;
|
*/
|
||||||
private short field_4_xf_index;
|
private int rwFirst;
|
||||||
private byte[] field_5_unknown;
|
|
||||||
private int field_6_label_opts;
|
|
||||||
private int field_7_url_len;
|
|
||||||
private int field_8_label_len;
|
|
||||||
private String field_9_label;
|
|
||||||
private byte[] field_10_unknown;
|
|
||||||
private int field_11_url_opts;
|
|
||||||
private String field_12_url;
|
|
||||||
|
|
||||||
/** Blank Constructor */
|
/**
|
||||||
|
* Last row of the hyperlink
|
||||||
|
*/
|
||||||
|
private int rwLast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First column of the hyperlink
|
||||||
|
*/
|
||||||
|
private short colFirst;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Last column of the hyperlink
|
||||||
|
*/
|
||||||
|
private short colLast;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 16-byte GUID
|
||||||
|
*/
|
||||||
|
private byte[] guid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some sort of options. Seems to always equal 2
|
||||||
|
*/
|
||||||
|
private int label_opts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some sort of options for file links.
|
||||||
|
*/
|
||||||
|
private short file_opts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link options. Can include any of HLINK_* flags.
|
||||||
|
*/
|
||||||
|
private int link_opts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test label
|
||||||
|
*/
|
||||||
|
private String label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moniker. Makes sense only for URL and file links
|
||||||
|
*/
|
||||||
|
private byte[] moniker;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link
|
||||||
|
*/
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remaining bytes
|
||||||
|
*/
|
||||||
|
private byte[] tail;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new hyperlink
|
||||||
|
*/
|
||||||
public HyperlinkRecord()
|
public HyperlinkRecord()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Real Constructor */
|
/**
|
||||||
|
* Read hyperlink from input stream
|
||||||
|
*
|
||||||
|
* @param in the stream to read from
|
||||||
|
*/
|
||||||
public HyperlinkRecord(RecordInputStream in)
|
public HyperlinkRecord(RecordInputStream in)
|
||||||
{
|
{
|
||||||
super(in);
|
super(in);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#getColumn()
|
* Return the column of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @return the 0-based column of the first cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public short getColumn()
|
public short getFirstColumn()
|
||||||
{
|
{
|
||||||
return field_3_column;
|
return colFirst;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#getRow()
|
* Set the column of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param col the 0-based column of the first cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public int getRow()
|
public void setFirstColumn(short col)
|
||||||
{
|
{
|
||||||
return field_2_row;
|
this.colFirst = col;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#getXFIndex()
|
* Set the column of the last cell that contains the hyperlink
|
||||||
*/
|
*
|
||||||
public short getXFIndex()
|
* @return the 0-based column of the last cell that contains the hyperlink
|
||||||
|
*/
|
||||||
|
public short getLastColumn()
|
||||||
{
|
{
|
||||||
return field_4_xf_index;
|
return colLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#isAfter(org.apache.poi.hssf.record.CellValueRecordInterface)
|
* Set the column of the last cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param col the 0-based column of the last cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public boolean isAfter(CellValueRecordInterface i)
|
public void setLastColumn(short col)
|
||||||
{
|
{
|
||||||
if (this.getRow() < i.getRow())
|
this.colLast = col;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((this.getRow() == i.getRow()) && (this.getColumn() < i.getColumn()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((this.getRow() == i.getRow()) && (this.getColumn() == i.getColumn()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#isBefore(org.apache.poi.hssf.record.CellValueRecordInterface)
|
* Return the row of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @return the 0-based row of the first cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public boolean isBefore(CellValueRecordInterface i)
|
public int getFirstRow()
|
||||||
{
|
{
|
||||||
if (this.getRow() > i.getRow())
|
return rwFirst;
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((this.getRow() == i.getRow()) && (this.getColumn() > i.getColumn()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if ((this.getRow() == i.getRow()) && (this.getColumn() == i.getColumn()))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#isEqual(org.apache.poi.hssf.record.CellValueRecordInterface)
|
* Set the row of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param row the 0-based row of the first cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public boolean isEqual(CellValueRecordInterface i)
|
public void setFirstRow(int row)
|
||||||
{
|
{
|
||||||
return ((this.getRow() == i.getRow()) && (this.getColumn() == i.getColumn()));
|
this.rwFirst = row;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#setColumn(short)
|
* Return the row of the last cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @return the 0-based row of the last cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public void setColumn(short col)
|
public int getLastRow()
|
||||||
{
|
{
|
||||||
this.field_3_column = col;
|
return rwLast;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#setRow(int)
|
* Set the row of the last cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param row the 0-based row of the last cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public void setRow(int row)
|
public void setLastRow(int row)
|
||||||
{
|
{
|
||||||
this.field_2_row = row;
|
this.rwLast = row;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
/**
|
||||||
* @see org.apache.poi.hssf.record.CellValueRecordInterface#setXFIndex(short)
|
* Returns a 16-byte guid identifier. Seems to always equal {@link STD_MONIKER}
|
||||||
|
*
|
||||||
|
* @return 16-byte guid identifier
|
||||||
*/
|
*/
|
||||||
public void setXFIndex(short xf)
|
public byte[] getGuid()
|
||||||
{
|
{
|
||||||
this.field_4_xf_index = xf;
|
return guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a 16-byte moniker.
|
||||||
|
*
|
||||||
|
* @return 16-byte moniker
|
||||||
|
*/
|
||||||
|
public byte[] getMoniker()
|
||||||
|
{
|
||||||
|
return moniker;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return text label for this hyperlink
|
||||||
|
*
|
||||||
|
* @return text to display
|
||||||
|
*/
|
||||||
|
public String getLabel()
|
||||||
|
{
|
||||||
|
int idx = label.indexOf('\u0000');
|
||||||
|
return idx == -1 ? label : label.substring(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text label for this hyperlink
|
||||||
|
*
|
||||||
|
* @param label text label for this hyperlink
|
||||||
|
*/
|
||||||
|
public void setLabel(String label)
|
||||||
|
{
|
||||||
|
this.label = label + '\u0000';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hypelink address. Depending on the hyperlink type it can be URL, e-mail, patrh to a file, etc.
|
||||||
|
*
|
||||||
|
* @return the address of this hyperlink
|
||||||
|
*/
|
||||||
|
public String getAddress()
|
||||||
|
{
|
||||||
|
int idx = address.indexOf('\u0000');
|
||||||
|
return idx == -1 ? address : address.substring(0, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hypelink address. Depending on the hyperlink type it can be URL, e-mail, patrh to a file, etc.
|
||||||
|
*
|
||||||
|
* @param address the address of this hyperlink
|
||||||
|
*/
|
||||||
|
public void setAddress(String address)
|
||||||
|
{
|
||||||
|
this.address = address + '\u0000';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Link options. Must be a combination of HLINK_* constants.
|
||||||
|
*/
|
||||||
|
public int getLinkOptions(){
|
||||||
|
return link_opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label options
|
||||||
|
*/
|
||||||
|
public int getLabelOptions(){
|
||||||
|
return label_opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Options for a file link
|
||||||
|
*/
|
||||||
|
public int getFileOptions(){
|
||||||
|
return file_opts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getTail(){
|
||||||
|
return tail;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -178,57 +313,56 @@ public class HyperlinkRecord extends Record implements CellValueRecordInterface
|
|||||||
*/
|
*/
|
||||||
protected void fillFields(RecordInputStream in)
|
protected void fillFields(RecordInputStream in)
|
||||||
{
|
{
|
||||||
// System.err.println(in.currentSid);
|
|
||||||
// System.err.println(in.currentLength);
|
|
||||||
// for(int i=0; i<300; i++) {
|
|
||||||
// System.err.println(in.readByte());
|
|
||||||
// }
|
|
||||||
// if(1==1)
|
|
||||||
// throw new IllegalArgumentException("");
|
|
||||||
|
|
||||||
field_1_unknown = in.readShort();
|
|
||||||
field_2_row = in.readUShort();
|
|
||||||
field_3_column = in.readShort();
|
|
||||||
field_4_xf_index = in.readShort();
|
|
||||||
|
|
||||||
// Next up is 16 bytes we don't get
|
|
||||||
field_5_unknown = new byte[16];
|
|
||||||
try {
|
try {
|
||||||
in.read(field_5_unknown);
|
rwFirst = in.readShort();
|
||||||
} catch(IOException e) { throw new IllegalStateException(e.getMessage()); }
|
rwLast = in.readUShort();
|
||||||
|
colFirst = in.readShort();
|
||||||
|
colLast = in.readShort();
|
||||||
|
|
||||||
// Some sort of opts
|
// 16-byte GUID
|
||||||
field_6_label_opts = in.readInt();
|
guid = new byte[16];
|
||||||
|
in.read(guid);
|
||||||
|
|
||||||
// Now for lengths, in characters
|
label_opts = in.readInt();
|
||||||
field_7_url_len = in.readInt();
|
link_opts = in.readInt();
|
||||||
field_8_label_len = in.readInt();
|
|
||||||
|
|
||||||
// Now we have the label, as little endian unicode,
|
if ((link_opts & HLINK_LABEL) != 0){
|
||||||
// with a trailing \0
|
int label_len = in.readInt();
|
||||||
field_9_label = in.readUnicodeLEString(field_8_label_len);
|
label = in.readUnicodeLEString(label_len);
|
||||||
|
}
|
||||||
|
|
||||||
// Next up is some more data we can't make sense of
|
if ((link_opts & HLINK_URL) != 0){
|
||||||
field_10_unknown = new byte[16];
|
moniker = new byte[16];
|
||||||
try {
|
in.read(moniker);
|
||||||
in.read(field_10_unknown);
|
|
||||||
} catch(IOException e) { throw new IllegalStateException(e.getMessage()); }
|
|
||||||
|
|
||||||
// Might need to nudge the length by one byte
|
if(Arrays.equals(URL_MONIKER, moniker)){
|
||||||
// This is an empirical hack!
|
int len = in.readInt();
|
||||||
field_11_url_opts = in.readInt();
|
|
||||||
if(field_11_url_opts == 44) {
|
address = in.readUnicodeLEString(len/2);
|
||||||
field_7_url_len--;
|
|
||||||
|
tail = in.readRemainder();
|
||||||
|
} else if (Arrays.equals(FILE_MONIKER, moniker)){
|
||||||
|
file_opts = in.readShort();
|
||||||
|
|
||||||
|
int len = in.readInt();
|
||||||
|
|
||||||
|
byte[] path_bytes = new byte[len];
|
||||||
|
in.read(path_bytes);
|
||||||
|
|
||||||
|
address = new String(path_bytes);
|
||||||
|
|
||||||
|
tail = in.readRemainder();
|
||||||
|
}
|
||||||
|
} else if((link_opts & HLINK_PLACE) != 0){
|
||||||
|
int len = in.readInt();
|
||||||
|
address = in.readUnicodeLEString(len);
|
||||||
|
}
|
||||||
|
} catch (IOException e){
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally it's the URL
|
|
||||||
int strlen = field_7_url_len > (in.remaining()/2) ? (in.remaining()/2) : field_7_url_len;
|
|
||||||
field_12_url = in.readUnicodeLEString(strlen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* (non-Javadoc)
|
|
||||||
* @see org.apache.poi.hssf.record.Record#getSid()
|
|
||||||
*/
|
|
||||||
public short getSid()
|
public short getSid()
|
||||||
{
|
{
|
||||||
return HyperlinkRecord.sid;
|
return HyperlinkRecord.sid;
|
||||||
@ -244,55 +378,75 @@ public class HyperlinkRecord extends Record implements CellValueRecordInterface
|
|||||||
|
|
||||||
public int serialize(int offset, byte[] data)
|
public int serialize(int offset, byte[] data)
|
||||||
{
|
{
|
||||||
LittleEndian.putShort(data, 0 + offset, sid);
|
int pos = offset;
|
||||||
LittleEndian.putShort(data, 2 + offset,
|
LittleEndian.putShort(data, pos, sid); pos += 2;
|
||||||
( short )(getRecordSize()-4));
|
LittleEndian.putShort(data, pos, ( short )(getRecordSize()-4)); pos += 2;
|
||||||
LittleEndian.putShort(data, 4 + offset, field_1_unknown);
|
LittleEndian.putUShort(data, pos, rwFirst); pos += 2;
|
||||||
LittleEndian.putUShort(data, 6 + offset, field_2_row);
|
LittleEndian.putUShort(data, pos, rwLast); pos += 2;
|
||||||
LittleEndian.putShort(data, 8 + offset, field_3_column);
|
LittleEndian.putShort(data, pos, colFirst); pos += 2;
|
||||||
LittleEndian.putShort(data, 10 + offset, field_4_xf_index);
|
LittleEndian.putShort(data, pos, colLast); pos += 2;
|
||||||
|
|
||||||
offset += 12;
|
System.arraycopy(guid, 0, data, pos, guid.length); pos += guid.length;
|
||||||
for(int i=0; i<field_5_unknown.length; i++) {
|
|
||||||
data[offset] = field_5_unknown[i];
|
LittleEndian.putInt(data, pos, label_opts); pos += 4;
|
||||||
offset++;
|
LittleEndian.putInt(data, pos, link_opts); pos += 4;
|
||||||
|
|
||||||
|
if ((link_opts & HLINK_LABEL) != 0){
|
||||||
|
LittleEndian.putInt(data, pos, label.length()); pos += 4;
|
||||||
|
StringUtil.putUnicodeLE(label, data, pos); pos += label.length()*2;
|
||||||
}
|
}
|
||||||
|
if ((link_opts & HLINK_URL) != 0){
|
||||||
LittleEndian.putInt(data, offset, field_6_label_opts);
|
System.arraycopy(moniker, 0, data, pos, moniker.length); pos += moniker.length;
|
||||||
offset += 4;
|
if(Arrays.equals(URL_MONIKER, moniker)){
|
||||||
LittleEndian.putInt(data, offset, field_7_url_len);
|
LittleEndian.putInt(data, pos, address.length()*2 + tail.length); pos += 4;
|
||||||
offset += 4;
|
StringUtil.putUnicodeLE(address, data, pos); pos += address.length()*2;
|
||||||
LittleEndian.putInt(data, offset, field_8_label_len);
|
if(tail.length > 0){
|
||||||
offset += 4;
|
System.arraycopy(tail, 0, data, pos, tail.length); pos += tail.length;
|
||||||
StringUtil.putUnicodeLE(field_9_label, data, offset);
|
}
|
||||||
offset += field_9_label.length()*2;
|
} else if (Arrays.equals(FILE_MONIKER, moniker)){
|
||||||
|
LittleEndian.putShort(data, pos, file_opts); pos += 2;
|
||||||
for(int i=0; i<field_10_unknown.length; i++) {
|
LittleEndian.putInt(data, pos, address.length()); pos += 4;
|
||||||
data[offset] = field_10_unknown[i];
|
byte[] bytes = address.getBytes();
|
||||||
offset++;
|
System.arraycopy(bytes, 0, data, pos, bytes.length); pos += bytes.length;
|
||||||
|
if(tail.length > 0){
|
||||||
|
System.arraycopy(tail, 0, data, pos, tail.length); pos += tail.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if((link_opts & HLINK_PLACE) != 0){
|
||||||
|
LittleEndian.putInt(data, pos, address.length()); pos += 4;
|
||||||
|
StringUtil.putUnicodeLE(address, data, pos); pos += address.length()*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
LittleEndian.putInt(data, offset, field_11_url_opts);
|
|
||||||
offset += 4;
|
|
||||||
StringUtil.putUnicodeLE(field_12_url, data, offset);
|
|
||||||
|
|
||||||
return getRecordSize();
|
return getRecordSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRecordSize()
|
public int getRecordSize()
|
||||||
{
|
{
|
||||||
// We have:
|
int size = 4;
|
||||||
// 4 shorts
|
size += 2 + 2 + 2 + 2; //rwFirst, rwLast, colFirst, colLast
|
||||||
// junk
|
size += guid.length;
|
||||||
// 3 ints
|
size += 4; //label_opts
|
||||||
// label
|
size += 4; //link_opts
|
||||||
// junk
|
if ((link_opts & HLINK_LABEL) != 0){
|
||||||
// int
|
size += 4; //link length
|
||||||
// url
|
size += label.length()*2;
|
||||||
return 4 + 4*2 + field_5_unknown.length +
|
}
|
||||||
3*4 + field_9_label.length()*2 +
|
if ((link_opts & HLINK_URL) != 0){
|
||||||
field_10_unknown.length + 4 +
|
size += moniker.length; //moniker length
|
||||||
field_12_url.length()*2;
|
if(Arrays.equals(URL_MONIKER, moniker)){
|
||||||
|
size += 4; //address length
|
||||||
|
size += address.length()*2;
|
||||||
|
size += tail.length;
|
||||||
|
} else if (Arrays.equals(FILE_MONIKER, moniker)){
|
||||||
|
size += 2; //file_opts
|
||||||
|
size += 4; //address length
|
||||||
|
size += address.length();
|
||||||
|
size += tail.length;
|
||||||
|
}
|
||||||
|
} else if((link_opts & HLINK_PLACE) != 0){
|
||||||
|
size += 4; //address length
|
||||||
|
size += address.length()*2;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString()
|
public String toString()
|
||||||
@ -300,71 +454,89 @@ public class HyperlinkRecord extends Record implements CellValueRecordInterface
|
|||||||
StringBuffer buffer = new StringBuffer();
|
StringBuffer buffer = new StringBuffer();
|
||||||
|
|
||||||
buffer.append("[HYPERLINK RECORD]\n");
|
buffer.append("[HYPERLINK RECORD]\n");
|
||||||
buffer.append(" .row = ").append(Integer.toHexString(getRow())).append("\n");
|
buffer.append(" .rwFirst = ").append(Integer.toHexString(getFirstRow())).append("\n");
|
||||||
buffer.append(" .column = ").append(Integer.toHexString(getColumn())).append("\n");
|
buffer.append(" .rwLast = ").append(Integer.toHexString(getLastRow())).append("\n");
|
||||||
buffer.append(" .xfindex = ").append(Integer.toHexString(getXFIndex())).append("\n");
|
buffer.append(" .colFirst = ").append(Integer.toHexString(getFirstColumn())).append("\n");
|
||||||
buffer.append(" .label = ").append(field_9_label).append("\n");
|
buffer.append(" .colLast = ").append(Integer.toHexString(getLastColumn())).append("\n");
|
||||||
buffer.append(" .url = ").append(field_12_url).append("\n");
|
buffer.append(" .guid = ").append(HexDump.toHex(guid)).append("\n");
|
||||||
|
buffer.append(" .label_opts = ").append(label_opts).append("\n");
|
||||||
|
buffer.append(" .label = ").append(getLabel()).append("\n");
|
||||||
|
if((link_opts & HLINK_URL) != 0){
|
||||||
|
buffer.append(" .moniker = ").append(HexDump.toHex(moniker)).append("\n");
|
||||||
|
}
|
||||||
|
buffer.append(" .address = ").append(getAddress()).append("\n");
|
||||||
buffer.append("[/HYPERLINK RECORD]\n");
|
buffer.append("[/HYPERLINK RECORD]\n");
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the label.
|
* Initialize a new url link
|
||||||
*/
|
*/
|
||||||
public String getLabel()
|
public void newUrlLink(){
|
||||||
{
|
rwFirst = 0;
|
||||||
if(field_9_label.length() == 0) {
|
rwLast = 0;
|
||||||
return "";
|
colFirst = 0;
|
||||||
} else {
|
colLast = 0;
|
||||||
// Trim off \0
|
guid = STD_MONIKER;
|
||||||
return field_9_label.substring(0, field_9_label.length() - 1);
|
label_opts = 0x2;
|
||||||
}
|
link_opts = HLINK_URL | HLINK_ABS | HLINK_LABEL;
|
||||||
|
label = "" + '\u0000';
|
||||||
|
moniker = URL_MONIKER;
|
||||||
|
address = "" + '\u0000';
|
||||||
|
tail = URL_TAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param label The label to set.
|
* Initialize a new file link
|
||||||
*/
|
*/
|
||||||
public void setLabel(String label)
|
public void newFileLink(){
|
||||||
{
|
rwFirst = 0;
|
||||||
this.field_9_label = label + '\u0000';
|
rwLast = 0;
|
||||||
this.field_8_label_len = field_9_label.length();
|
colFirst = 0;
|
||||||
|
colLast = 0;
|
||||||
|
guid = STD_MONIKER;
|
||||||
|
label_opts = 0x2;
|
||||||
|
link_opts = HLINK_URL | HLINK_LABEL;
|
||||||
|
file_opts = 0;
|
||||||
|
label = "" + '\u0000';
|
||||||
|
moniker = FILE_MONIKER;
|
||||||
|
address = "" + '\0';
|
||||||
|
tail = FILE_TAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns the Url.
|
* Initialize a new document link
|
||||||
*/
|
*/
|
||||||
public URL getUrl() throws MalformedURLException
|
public void newDocumentLink(){
|
||||||
{
|
rwFirst = 0;
|
||||||
return new URL(getUrlString());
|
rwLast = 0;
|
||||||
}
|
colFirst = 0;
|
||||||
public String getUrlString()
|
colLast = 0;
|
||||||
{
|
guid = STD_MONIKER;
|
||||||
if(field_12_url.length() == 0) {
|
label_opts = 0x2;
|
||||||
return "";
|
link_opts = HLINK_LABEL | HLINK_PLACE;
|
||||||
} else {
|
label = "" + '\u0000';
|
||||||
// Trim off \0
|
moniker = FILE_MONIKER;
|
||||||
return field_12_url.substring(0, field_12_url.length() - 1);
|
address = "" + '\0';
|
||||||
}
|
tail = new byte[]{};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public Object clone() {
|
||||||
* @param url The url to set.
|
HyperlinkRecord rec = new HyperlinkRecord();
|
||||||
*/
|
rec.rwFirst = rwFirst;
|
||||||
public void setUrl(URL url)
|
rec.rwLast = rwLast;
|
||||||
{
|
rec.colFirst = colFirst;
|
||||||
setUrl(url.toString());
|
rec.colLast = colLast;
|
||||||
}
|
rec.guid = guid;
|
||||||
/**
|
rec.label_opts = label_opts;
|
||||||
* @param url The url to set.
|
rec.link_opts = link_opts;
|
||||||
*/
|
rec.file_opts = file_opts;
|
||||||
public void setUrl(String url)
|
rec.label = label;
|
||||||
{
|
rec.address = address;
|
||||||
this.field_12_url = url + '\u0000';
|
rec.moniker = moniker;
|
||||||
this.field_7_url_len = field_12_url.length();
|
rec.tail = tail;
|
||||||
|
return rec;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getOptions(){
|
|
||||||
return field_11_url_opts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1066,7 +1066,7 @@ public class HSSFCell
|
|||||||
Record rec = ( Record ) it.next();
|
Record rec = ( Record ) it.next();
|
||||||
if (rec instanceof HyperlinkRecord){
|
if (rec instanceof HyperlinkRecord){
|
||||||
HyperlinkRecord link = (HyperlinkRecord)rec;
|
HyperlinkRecord link = (HyperlinkRecord)rec;
|
||||||
if(link.getColumn() == record.getColumn() && link.getRow() == record.getRow()){
|
if(link.getFirstColumn() == record.getColumn() && link.getFirstRow() == record.getRow()){
|
||||||
return new HSSFHyperlink(link);
|
return new HSSFHyperlink(link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1080,6 +1080,25 @@ public class HSSFCell
|
|||||||
* @param link hypelrink associated with this cell
|
* @param link hypelrink associated with this cell
|
||||||
*/
|
*/
|
||||||
public void setHyperlink(HSSFHyperlink link){
|
public void setHyperlink(HSSFHyperlink link){
|
||||||
|
link.setFirstRow(record.getRow());
|
||||||
|
link.setLastRow(record.getRow());
|
||||||
|
link.setFirstColumn(record.getColumn());
|
||||||
|
link.setLastColumn(record.getColumn());
|
||||||
|
|
||||||
|
switch(link.getType()){
|
||||||
|
case HSSFHyperlink.LINK_EMAIL:
|
||||||
|
case HSSFHyperlink.LINK_URL:
|
||||||
|
link.setLabel("url");
|
||||||
|
break;
|
||||||
|
case HSSFHyperlink.LINK_FILE:
|
||||||
|
link.setLabel("file");
|
||||||
|
break;
|
||||||
|
case HSSFHyperlink.LINK_DOCUMENT:
|
||||||
|
link.setLabel("place");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
int eofLoc = sheet.findFirstRecordLocBySid( EOFRecord.sid );
|
||||||
|
sheet.getRecords().add( eofLoc, link.record );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ import java.util.List;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a hyperlink.
|
* Represents an Excel hyperlink.
|
||||||
*
|
*
|
||||||
* @author Yegor Kozlov
|
* @author Yegor Kozlov (yegor at apache dot org)
|
||||||
*/
|
*/
|
||||||
public class HSSFHyperlink {
|
public class HSSFHyperlink {
|
||||||
|
|
||||||
@ -49,67 +49,145 @@ public class HSSFHyperlink {
|
|||||||
public static final int LINK_EMAIL = 3;
|
public static final int LINK_EMAIL = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unknown type
|
* Link to a file
|
||||||
*/
|
*/
|
||||||
public static final int LINK_UNKNOWN = 4;
|
public static final int LINK_FILE = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Low-level record object that stores the actual hyperlink data
|
* Low-level record object that stores the actual hyperlink data
|
||||||
*/
|
*/
|
||||||
private HyperlinkRecord record = null;
|
protected HyperlinkRecord record = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If we create a new hypelrink remember its type
|
||||||
|
*/
|
||||||
|
protected int link_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new hyperlink
|
||||||
|
*
|
||||||
|
* @param type the type of hyperlink to create
|
||||||
|
*/
|
||||||
|
public HSSFHyperlink( int type )
|
||||||
|
{
|
||||||
|
this.link_type = type;
|
||||||
|
record = new HyperlinkRecord();
|
||||||
|
switch(type){
|
||||||
|
case LINK_URL:
|
||||||
|
case LINK_EMAIL:
|
||||||
|
record.newUrlLink();
|
||||||
|
break;
|
||||||
|
case LINK_FILE:
|
||||||
|
record.newFileLink();
|
||||||
|
break;
|
||||||
|
case LINK_DOCUMENT:
|
||||||
|
record.newDocumentLink();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the hyperlink by a <code>HyperlinkRecord</code> record
|
||||||
|
*
|
||||||
|
* @param record
|
||||||
|
*/
|
||||||
protected HSSFHyperlink( HyperlinkRecord record )
|
protected HSSFHyperlink( HyperlinkRecord record )
|
||||||
{
|
{
|
||||||
this.record = record;
|
this.record = record;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the row of the cell that contains the hyperlink
|
* Return the row of the first cell that contains the hyperlink
|
||||||
*
|
*
|
||||||
* @return the 0-based row of the cell that contains the hyperlink
|
* @return the 0-based row of the cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public int getRow(){
|
public int getFirstRow(){
|
||||||
return record.getRow();
|
return record.getFirstRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the row of the cell that contains the hyperlink
|
* Set the row of the first cell that contains the hyperlink
|
||||||
*
|
*
|
||||||
* @param row the 0-based row of the cell that contains the hyperlink
|
* @param row the 0-based row of the first cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public void setRow(int row){
|
public void setFirstRow(int row){
|
||||||
record.setRow(row);
|
record.setFirstRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the column of the cell that contains the hyperlink
|
* Return the row of the last cell that contains the hyperlink
|
||||||
*
|
*
|
||||||
* @return the 0-based column of the cell that contains the hyperlink
|
* @return the 0-based row of the last cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public short getColumn(){
|
public int getLastRow(){
|
||||||
return record.getColumn();
|
return record.getLastRow();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the column of the cell that contains the hyperlink
|
* Set the row of the last cell that contains the hyperlink
|
||||||
*
|
*
|
||||||
* @param col the 0-based column of the cell that contains the hyperlink
|
* @param row the 0-based row of the last cell that contains the hyperlink
|
||||||
*/
|
*/
|
||||||
public void setColumn(short col){
|
public void setLastRow(int row){
|
||||||
record.setColumn(col);
|
record.setLastRow(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hypelink address. Depending on the hyperlink type it can be URL, e-mail, etc.
|
* Return the column of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @return the 0-based column of the first cell that contains the hyperlink
|
||||||
|
*/
|
||||||
|
public short getFirstColumn(){
|
||||||
|
return record.getFirstColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the column of the first cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param col the 0-based column of the first cell that contains the hyperlink
|
||||||
|
*/
|
||||||
|
public void setFirstColumn(short col){
|
||||||
|
record.setFirstColumn(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the column of the last cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @return the 0-based column of the last cell that contains the hyperlink
|
||||||
|
*/
|
||||||
|
public short getLastColumn(){
|
||||||
|
return record.getLastColumn();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the column of the last cell that contains the hyperlink
|
||||||
|
*
|
||||||
|
* @param col the 0-based column of the last cell that contains the hyperlink
|
||||||
|
*/
|
||||||
|
public void setLastColumn(short col){
|
||||||
|
record.setLastColumn(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hypelink address. Depending on the hyperlink type it can be URL, e-mail, patrh to a file, etc.
|
||||||
*
|
*
|
||||||
* @return the address of this hyperlink
|
* @return the address of this hyperlink
|
||||||
*/
|
*/
|
||||||
public String getAddress(){
|
public String getAddress(){
|
||||||
return record.getUrlString();
|
return record.getAddress();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return text to display for this hyperlink
|
* Hypelink address. Depending on the hyperlink type it can be URL, e-mail, patrh to a file, etc.
|
||||||
|
*
|
||||||
|
* @param address the address of this hyperlink
|
||||||
|
*/
|
||||||
|
public void setAddress(String address){
|
||||||
|
record.setAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return text label for this hyperlink
|
||||||
*
|
*
|
||||||
* @return text to display
|
* @return text to display
|
||||||
*/
|
*/
|
||||||
@ -117,12 +195,21 @@ public class HSSFHyperlink {
|
|||||||
return record.getLabel();
|
return record.getLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets text label for this hyperlink
|
||||||
|
*
|
||||||
|
* @param label text label for this hyperlink
|
||||||
|
*/
|
||||||
|
public void setLabel(String label){
|
||||||
|
record.setLabel(label);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the type of this hyperlink
|
* Return the type of this hyperlink
|
||||||
*
|
*
|
||||||
* @return the type of this hyperlink
|
* @return the type of this hyperlink
|
||||||
*/
|
*/
|
||||||
public int getType(){
|
protected int getType(){
|
||||||
throw new RuntimeException("Not implemented");
|
return link_type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,114 +18,311 @@ package org.apache.poi.hssf.record;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test HyperlinkRecord
|
||||||
|
*
|
||||||
|
* @author Nick Burch
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
public class TestHyperlinkRecord extends TestCase {
|
public class TestHyperlinkRecord extends TestCase {
|
||||||
protected void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
}
|
|
||||||
|
|
||||||
private byte[] data = new byte[] {
|
//link to http://www.lakings.com/
|
||||||
-72, 1, 110, 0,
|
byte[] data1 = { 0x02, 0x00, //First row of the hyperlink
|
||||||
// ??, Row, col, xf
|
0x02, 0x00, //Last row of the hyperlink
|
||||||
6, 0, 3, 0, 2, 0, 2, 0,
|
0x00, 0x00, //First column of the hyperlink
|
||||||
|
0x00, 0x00, //Last column of the hyperlink
|
||||||
|
|
||||||
// ??
|
//16-byte GUID. Seems to be always the same. Does not depend on the hyperlink type
|
||||||
-48, -55, -22, 121, -7, -70, -50, 17,
|
(byte)0xD0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
-116, -126, 0, -86, 0, 75, -87, 11,
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
2, 0, 0, 0,
|
|
||||||
|
|
||||||
// URL length
|
0x02, 0x00, 0x00, 0x00, //integer, always 2
|
||||||
23, 0, 0, 0,
|
|
||||||
|
|
||||||
// Label length
|
// flags. Define the type of the hyperlink:
|
||||||
4, 0, 0, 0,
|
// HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL
|
||||||
|
0x17, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
// Label
|
0x08, 0x00, 0x00, 0x00, //length of the label including the trailing '\0'
|
||||||
76, 0, 44, 0, 65, 0, 0, 0,
|
|
||||||
|
|
||||||
// ??
|
//label:
|
||||||
-32, -55, -22, 121, -7, -70, -50, 17,
|
0x4D, 0x00, 0x79, 0x00, 0x20, 0x00, 0x4C, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x6B, 0x00, 0x00, 0x00,
|
||||||
-116, -126, 0, -86, 0, 75, -87, 11,
|
|
||||||
46, 0, 0, 0,
|
|
||||||
|
|
||||||
// URL
|
//16-byte link moniker: HyperlinkRecord.URL_MONIKER
|
||||||
104, 0, 116, 0, 116, 0, 112, 0, 58, 0, 47, 0, 47, 0, 119,
|
(byte)0xE0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
0, 119, 0, 119, 0, 46, 0, 108, 0, 97, 0, 107, 0, 105,
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
0, 110, 0, 103, 0, 115, 0, 46, 0, 99, 0, 111, 0,
|
|
||||||
109, 0,
|
|
||||||
0, 0 };
|
|
||||||
|
|
||||||
private byte[] data2 = new byte[] {
|
//count of bytes in the address including the tail
|
||||||
-72, 1, -126, 0,
|
0x48, 0x00, 0x00, 0x00, //integer
|
||||||
// ??, Row, col, xf
|
|
||||||
2, 0, 2, 0, 4, 0, 4, 0,
|
|
||||||
|
|
||||||
// ??
|
//the actual link, terminated by '\u0000'
|
||||||
-48, -55, -22, 121, -7, -70, -50, 17,
|
0x68, 0x00, 0x74, 0x00, 0x74, 0x00, 0x70, 0x00, 0x3A, 0x00, 0x2F, 0x00,
|
||||||
-116, -126, 0, -86, 0, 75, -87, 11,
|
0x2F, 0x00, 0x77, 0x00, 0x77, 0x00, 0x77, 0x00, 0x2E, 0x00, 0x6C, 0x00,
|
||||||
2, 0, 0, 0,
|
0x61, 0x00, 0x6B, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00, 0x73, 0x00,
|
||||||
|
0x2E, 0x00, 0x63, 0x00, 0x6F, 0x00, 0x6D, 0x00, 0x2F, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
// URL and Label lengths
|
//standard 24-byte tail of a URL link. Seems to always be the same for all URL HLINKs
|
||||||
23, 0, 0, 0,
|
0x79, 0x58, (byte)0x81, (byte)0xF4, 0x3B, 0x1D, 0x7F, 0x48, (byte)0xAF, 0x2C,
|
||||||
15, 0, 0, 0,
|
(byte)0x82, 0x5D, (byte)0xC4, (byte)0x85, 0x27, 0x63, 0x00, 0x00, 0x00,
|
||||||
|
0x00, (byte)0xA5, (byte)0xAB, 0x00, 0x00};
|
||||||
|
|
||||||
// Label
|
//link to a file in the current directory: link1.xls
|
||||||
83, 0, 116, 0, 97, 0, 99, 0, 105, 0,
|
byte[] data2 = {0x00, 0x00,
|
||||||
101, 0, 64, 0, 65, 0, 66, 0, 67, 0,
|
0x00, 0x00,
|
||||||
46, 0, 99, 0, 111, 0, 109, 0, 0, 0,
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
//16-bit GUID. Seems to be always the same. Does not depend on the hyperlink type
|
||||||
|
(byte)0xD0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
|
|
||||||
// ??
|
0x02, 0x00, 0x00, 0x00, //integer, always 2
|
||||||
-32, -55, -22, 121, -7, -70, -50, 17,
|
|
||||||
-116, -126, 0, -86, 0, 75, -87, 11,
|
|
||||||
44, 0, 0, 0,
|
|
||||||
|
|
||||||
// URL
|
0x15, 0x00, 0x00, 0x00, //options: HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_LABEL
|
||||||
109, 0, 97, 0, 105, 0, 108, 0, 116, 0,
|
|
||||||
111, 0, 58, 0, 83, 0, 116, 0, 97, 0,
|
|
||||||
99, 0, 105, 0, 101, 0, 64, 0, 65, 0,
|
|
||||||
66, 0, 67, 0, 46, 0, 99, 0, 111, 0,
|
|
||||||
109, 0, 0, 0 };
|
|
||||||
|
|
||||||
public void testRecordParsing() throws Exception {
|
0x05, 0x00, 0x00, 0x00, //length of the label
|
||||||
RecordInputStream inp = new RecordInputStream(
|
//label
|
||||||
new ByteArrayInputStream(data)
|
0x66, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x65, 0x00, 0x00, 0x00,
|
||||||
);
|
|
||||||
inp.nextRecord();
|
|
||||||
|
|
||||||
HyperlinkRecord r = new HyperlinkRecord(inp);
|
//16-byte link moniker: HyperlinkRecord.FILE_MONIKER
|
||||||
|
0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, (byte)0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46,
|
||||||
|
|
||||||
assertEquals(3, r.getRow());
|
0x00, 0x00, //level
|
||||||
assertEquals(2, r.getColumn());
|
0x0A, 0x00, 0x00, 0x00, //length of the path )
|
||||||
assertEquals(2, r.getXFIndex());
|
|
||||||
|
|
||||||
assertEquals("L,A", r.getLabel());
|
//path to the file (plain ISO-8859 bytes, NOT UTF-16LE!)
|
||||||
assertEquals("http://www.lakings.com", r.getUrlString());
|
0x6C, 0x69, 0x6E, 0x6B, 0x31, 0x2E, 0x78, 0x6C, 0x73, 0x00,
|
||||||
assertEquals(new URL("http://www.lakings.com"), r.getUrl());
|
|
||||||
|
|
||||||
// Check it serialises as expected
|
//standard 28-byte tail of a file link
|
||||||
assertEquals(data.length, r.getRecordSize());
|
(byte)0xFF, (byte)0xFF, (byte)0xAD, (byte)0xDE, 0x00, 0x00, 0x00, 0x00,
|
||||||
byte[] d = r.serialize();
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
assertEquals(data.length, d.length);
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
for(int i=0; i<data.length; i++) {
|
|
||||||
assertEquals(data[i], d[i]);
|
// mailto:ebgans@mail.ru?subject=Hello,%20Ebgans!
|
||||||
|
byte[] data3 = {0x01, 0x00,
|
||||||
|
0x01, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
|
||||||
|
//16-bit GUID. Seems to be always the same. Does not depend on the hyperlink type
|
||||||
|
(byte)0xD0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
|
|
||||||
|
0x02, 0x00, 0x00, 0x00, //integer, always 2
|
||||||
|
|
||||||
|
0x17, 0x00, 0x00, 0x00, //options: HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL
|
||||||
|
|
||||||
|
0x06, 0x00, 0x00, 0x00, //length of the label
|
||||||
|
0x65, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x00, 0x00, //label
|
||||||
|
|
||||||
|
//16-byte link moniker: HyperlinkRecord.URL_MONIKER
|
||||||
|
(byte)0xE0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
|
|
||||||
|
//length of the address including the tail.
|
||||||
|
0x76, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
//the address is terminated by '\u0000'
|
||||||
|
0x6D, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6C, 0x00, 0x74, 0x00, 0x6F, 0x00,
|
||||||
|
0x3A, 0x00, 0x65, 0x00, 0x62, 0x00, 0x67, 0x00, 0x61, 0x00, 0x6E, 0x00,
|
||||||
|
0x73, 0x00, 0x40, 0x00, 0x6D, 0x00, 0x61, 0x00, 0x69, 0x00, 0x6C, 0x00,
|
||||||
|
0x2E, 0x00, 0x72, 0x00, 0x75, 0x00, 0x3F, 0x00, 0x73, 0x00, 0x75, 0x00,
|
||||||
|
0x62, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x3D, 0x00,
|
||||||
|
0x48, 0x00, 0x65, 0x00, 0x6C, 0x00, 0x6C, 0x00, 0x6F, 0x00, 0x2C, 0x00,
|
||||||
|
0x25, 0x00, 0x32, 0x00, 0x30, 0x00, 0x45, 0x00, 0x62, 0x00, 0x67, 0x00,
|
||||||
|
0x61, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x21, 0x00, 0x00, 0x00,
|
||||||
|
|
||||||
|
//standard 24-byte tail of a URL link
|
||||||
|
0x79, 0x58, (byte)0x81, (byte)0xF4, 0x3B, 0x1D, 0x7F, 0x48, (byte)0xAF, (byte)0x2C,
|
||||||
|
(byte)0x82, 0x5D, (byte)0xC4, (byte)0x85, 0x27, 0x63, 0x00, 0x00, 0x00,
|
||||||
|
0x00, (byte)0xA5, (byte)0xAB, 0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
//link to a place in worksheet: Sheet1!A1
|
||||||
|
byte[] data4 = {0x03, 0x00,
|
||||||
|
0x03, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
0x00, 0x00,
|
||||||
|
|
||||||
|
//16-bit GUID. Seems to be always the same. Does not depend on the hyperlink type
|
||||||
|
(byte)0xD0, (byte)0xC9, (byte)0xEA, 0x79, (byte)0xF9, (byte)0xBA, (byte)0xCE, 0x11,
|
||||||
|
(byte)0x8C, (byte)0x82, 0x00, (byte)0xAA, 0x00, 0x4B, (byte)0xA9, 0x0B,
|
||||||
|
|
||||||
|
0x02, 0x00, 0x00, 0x00, //integer, always 2
|
||||||
|
|
||||||
|
0x1C, 0x00, 0x00, 0x00, //flags: HyperlinkRecord.HLINK_LABEL | HyperlinkRecord.HLINK_PLACE
|
||||||
|
|
||||||
|
0x06, 0x00, 0x00, 0x00, //length of the label
|
||||||
|
|
||||||
|
0x70, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00, 0x00, 0x00, //label
|
||||||
|
|
||||||
|
0x0A, 0x00, 0x00, 0x00, //length of the document link including trailing zero
|
||||||
|
|
||||||
|
//link: Sheet1!A1
|
||||||
|
0x53, 0x00, 0x68, 0x00, 0x65, 0x00, 0x65, 0x00, 0x74, 0x00, 0x31, 0x00, 0x21,
|
||||||
|
0x00, 0x41, 0x00, 0x31, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
public void testReadURLLink(){
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data1.length, data1);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
assertEquals(2, link.getFirstRow());
|
||||||
|
assertEquals(2, link.getLastRow());
|
||||||
|
assertEquals(0, link.getFirstColumn());
|
||||||
|
assertEquals(0, link.getLastColumn());
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.STD_MONIKER, link.getGuid()));
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.URL_MONIKER, link.getMoniker()));
|
||||||
|
assertEquals(2, link.getLabelOptions());
|
||||||
|
int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL;
|
||||||
|
assertEquals(0x17, opts);
|
||||||
|
assertEquals(opts, link.getLinkOptions());
|
||||||
|
assertEquals(0, link.getFileOptions());
|
||||||
|
|
||||||
|
assertEquals("My Link", link.getLabel());
|
||||||
|
assertEquals("http://www.lakings.com/", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadFileLink(){
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data2.length, data2);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
assertEquals(0, link.getFirstRow());
|
||||||
|
assertEquals(0, link.getLastRow());
|
||||||
|
assertEquals(0, link.getFirstColumn());
|
||||||
|
assertEquals(0, link.getLastColumn());
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.STD_MONIKER, link.getGuid()));
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.FILE_MONIKER, link.getMoniker()));
|
||||||
|
assertEquals(2, link.getLabelOptions());
|
||||||
|
int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_LABEL;
|
||||||
|
assertEquals(0x15, opts);
|
||||||
|
assertEquals(opts, link.getLinkOptions());
|
||||||
|
|
||||||
|
assertEquals("file", link.getLabel());
|
||||||
|
assertEquals("link1.xls", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadEmailLink(){
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data3.length, data3);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
assertEquals(1, link.getFirstRow());
|
||||||
|
assertEquals(1, link.getLastRow());
|
||||||
|
assertEquals(0, link.getFirstColumn());
|
||||||
|
assertEquals(0, link.getLastColumn());
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.STD_MONIKER, link.getGuid()));
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.URL_MONIKER, link.getMoniker()));
|
||||||
|
assertEquals(2, link.getLabelOptions());
|
||||||
|
int opts = HyperlinkRecord.HLINK_URL | HyperlinkRecord.HLINK_ABS | HyperlinkRecord.HLINK_LABEL;
|
||||||
|
assertEquals(0x17, opts);
|
||||||
|
assertEquals(opts, link.getLinkOptions());
|
||||||
|
|
||||||
|
assertEquals("email", link.getLabel());
|
||||||
|
assertEquals("mailto:ebgans@mail.ru?subject=Hello,%20Ebgans!", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testReadDocumentLink(){
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data4.length, data4);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
assertEquals(3, link.getFirstRow());
|
||||||
|
assertEquals(3, link.getLastRow());
|
||||||
|
assertEquals(0, link.getFirstColumn());
|
||||||
|
assertEquals(0, link.getLastColumn());
|
||||||
|
assertTrue(Arrays.equals(HyperlinkRecord.STD_MONIKER, link.getGuid()));
|
||||||
|
assertEquals(2, link.getLabelOptions());
|
||||||
|
int opts = HyperlinkRecord.HLINK_LABEL | HyperlinkRecord.HLINK_PLACE;
|
||||||
|
assertEquals(0x1C, opts);
|
||||||
|
assertEquals(opts, link.getLinkOptions());
|
||||||
|
|
||||||
|
assertEquals("place", link.getLabel());
|
||||||
|
assertEquals("Sheet1!A1", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void serialize(byte[] data){
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data.length, data);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
byte[] bytes1 = link.serialize();
|
||||||
|
is = new RecordInputStream(new ByteArrayInputStream(bytes1));
|
||||||
|
is.nextRecord();
|
||||||
|
link = new HyperlinkRecord(is);
|
||||||
|
byte[] bytes2 = link.serialize();
|
||||||
|
assertEquals(bytes1.length, bytes2.length);
|
||||||
|
assertTrue(Arrays.equals(bytes1, bytes2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSerialize(){
|
||||||
|
serialize(data1);
|
||||||
|
serialize(data2);
|
||||||
|
serialize(data3);
|
||||||
|
serialize(data4);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateURLRecord() throws Exception {
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord();
|
||||||
|
link.newUrlLink();
|
||||||
|
link.setFirstRow((short)2);
|
||||||
|
link.setLastRow((short)2);
|
||||||
|
link.setLabel("My Link");
|
||||||
|
link.setAddress("http://www.lakings.com/");
|
||||||
|
|
||||||
|
byte[] tmp = link.serialize();
|
||||||
|
byte[] ser = new byte[tmp.length-4];
|
||||||
|
System.arraycopy(tmp, 4, ser, 0, ser.length);
|
||||||
|
assertEquals(data1.length, ser.length);
|
||||||
|
assertTrue(Arrays.equals(data1, ser));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateFileRecord() throws Exception {
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord();
|
||||||
|
link.newFileLink();
|
||||||
|
link.setFirstRow((short)0);
|
||||||
|
link.setLastRow((short)0);
|
||||||
|
link.setLabel("file");
|
||||||
|
link.setAddress("link1.xls");
|
||||||
|
|
||||||
|
byte[] tmp = link.serialize();
|
||||||
|
byte[] ser = new byte[tmp.length-4];
|
||||||
|
System.arraycopy(tmp, 4, ser, 0, ser.length);
|
||||||
|
assertEquals(data2.length, ser.length);
|
||||||
|
assertTrue(Arrays.equals(data2, ser));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateDocumentRecord() throws Exception {
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord();
|
||||||
|
link.newDocumentLink();
|
||||||
|
link.setFirstRow((short)3);
|
||||||
|
link.setLastRow((short)3);
|
||||||
|
link.setLabel("place");
|
||||||
|
link.setAddress("Sheet1!A1");
|
||||||
|
|
||||||
|
byte[] tmp = link.serialize();
|
||||||
|
byte[] ser = new byte[tmp.length-4];
|
||||||
|
System.arraycopy(tmp, 4, ser, 0, ser.length);
|
||||||
|
assertEquals(data4.length, ser.length);
|
||||||
|
assertTrue(Arrays.equals(data4, ser));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreateEmailtRecord() throws Exception {
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord();
|
||||||
|
link.newUrlLink();
|
||||||
|
link.setFirstRow((short)1);
|
||||||
|
link.setLastRow((short)1);
|
||||||
|
link.setLabel("email");
|
||||||
|
link.setAddress("mailto:ebgans@mail.ru?subject=Hello,%20Ebgans!");
|
||||||
|
|
||||||
|
byte[] tmp = link.serialize();
|
||||||
|
byte[] ser = new byte[tmp.length-4];
|
||||||
|
System.arraycopy(tmp, 4, ser, 0, ser.length);
|
||||||
|
assertEquals(data3.length, ser.length);
|
||||||
|
assertTrue(Arrays.equals(data3, ser));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClone() throws Exception {
|
||||||
|
byte[][] data = {data1, data2, data3, data4};
|
||||||
|
for (int i = 0; i < data.length; i++) {
|
||||||
|
RecordInputStream is = new TestcaseRecordInputStream((short)HyperlinkRecord.sid, (short)data[i].length, data[i]);
|
||||||
|
HyperlinkRecord link = new HyperlinkRecord(is);
|
||||||
|
HyperlinkRecord clone = (HyperlinkRecord)link.clone();
|
||||||
|
assertTrue(Arrays.equals(link.serialize(), clone.serialize()));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void testSecondRecord() throws Exception {
|
}
|
||||||
RecordInputStream inp = new RecordInputStream(
|
|
||||||
new ByteArrayInputStream(data2)
|
|
||||||
);
|
|
||||||
inp.nextRecord();
|
|
||||||
|
|
||||||
HyperlinkRecord r = new HyperlinkRecord(inp);
|
|
||||||
|
|
||||||
assertEquals(2, r.getRow());
|
|
||||||
assertEquals(4, r.getColumn());
|
|
||||||
assertEquals(4, r.getXFIndex());
|
|
||||||
|
|
||||||
assertEquals("Stacie@ABC.com", r.getLabel());
|
|
||||||
assertEquals("mailto:Stacie@ABC.com", r.getUrlString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -320,8 +320,8 @@ extends TestCase {
|
|||||||
|
|
||||||
assertEquals("Foo", link.getLabel());
|
assertEquals("Foo", link.getLabel());
|
||||||
assertEquals("http://poi.apache.org/", link.getAddress());
|
assertEquals("http://poi.apache.org/", link.getAddress());
|
||||||
assertEquals(4, link.getRow());
|
assertEquals(4, link.getFirstRow());
|
||||||
assertEquals(0, link.getColumn());
|
assertEquals(0, link.getFirstColumn());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -339,16 +339,16 @@ extends TestCase {
|
|||||||
assertNotNull(link1);
|
assertNotNull(link1);
|
||||||
assertEquals("Foo", link1.getLabel());
|
assertEquals("Foo", link1.getLabel());
|
||||||
assertEquals("http://poi.apache.org/", link1.getAddress());
|
assertEquals("http://poi.apache.org/", link1.getAddress());
|
||||||
assertEquals(4, link1.getRow());
|
assertEquals(4, link1.getFirstRow());
|
||||||
assertEquals(0, link1.getColumn());
|
assertEquals(0, link1.getFirstColumn());
|
||||||
|
|
||||||
HSSFCell cell2 = sheet.getRow(8).getCell((short)1);
|
HSSFCell cell2 = sheet.getRow(8).getCell((short)1);
|
||||||
HSSFHyperlink link2 = cell2.getHyperlink();
|
HSSFHyperlink link2 = cell2.getHyperlink();
|
||||||
assertNotNull(link2);
|
assertNotNull(link2);
|
||||||
assertEquals("Bar", link2.getLabel());
|
assertEquals("Bar", link2.getLabel());
|
||||||
assertEquals("http://poi.apache.org/", link2.getAddress());
|
assertEquals("http://poi.apache.org/hssf/", link2.getAddress());
|
||||||
assertEquals(8, link2.getRow());
|
assertEquals(8, link2.getFirstRow());
|
||||||
assertEquals(1, link2.getColumn());
|
assertEquals(1, link2.getFirstColumn());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
191
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFHyperlink.java
Executable file
191
src/testcases/org/apache/poi/hssf/usermodel/TestHSSFHyperlink.java
Executable file
@ -0,0 +1,191 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.hssf.usermodel;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests HSSFHyperlink.
|
||||||
|
*
|
||||||
|
* @author Yegor Kozlov
|
||||||
|
*/
|
||||||
|
public class TestHSSFHyperlink extends TestCase {
|
||||||
|
protected String cwd = System.getProperty("HSSF.testdata.path");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that we can read hyperlinks.
|
||||||
|
*/
|
||||||
|
public void testRead() throws Exception {
|
||||||
|
|
||||||
|
FileInputStream is = new FileInputStream(new File(cwd, "HyperlinksOnManySheets.xls"));
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
HSSFSheet sheet;
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFHyperlink link;
|
||||||
|
|
||||||
|
sheet = wb.getSheet("WebLinks");
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("POI", link.getLabel());
|
||||||
|
assertEquals("POI", cell.getRichStringCellValue().getString());
|
||||||
|
assertEquals("http://poi.apache.org/", link.getAddress());
|
||||||
|
|
||||||
|
cell = sheet.getRow(8).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("HSSF", link.getLabel());
|
||||||
|
assertEquals("HSSF", cell.getRichStringCellValue().getString());
|
||||||
|
assertEquals("http://poi.apache.org/hssf/", link.getAddress());
|
||||||
|
|
||||||
|
sheet = wb.getSheet("Emails");
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("dev", link.getLabel());
|
||||||
|
assertEquals("dev", cell.getRichStringCellValue().getString());
|
||||||
|
assertEquals("mailto:dev@poi.apache.org", link.getAddress());
|
||||||
|
|
||||||
|
sheet = wb.getSheet("Internal");
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("Link To First Sheet", link.getLabel());
|
||||||
|
assertEquals("Link To First Sheet", cell.getRichStringCellValue().getString());
|
||||||
|
assertEquals("WebLinks!A1", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModify() throws Exception {
|
||||||
|
FileInputStream is = new FileInputStream(new File(cwd, "HyperlinksOnManySheets.xls"));
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
HSSFSheet sheet;
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFHyperlink link;
|
||||||
|
|
||||||
|
sheet = wb.getSheet("WebLinks");
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
//modify the link
|
||||||
|
link.setAddress("www.apache.org");
|
||||||
|
|
||||||
|
//serialize and read again
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
wb.write(out);
|
||||||
|
|
||||||
|
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
sheet = wb.getSheet("WebLinks");
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("www.apache.org", link.getAddress());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCreate() throws Exception {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFSheet sheet = wb.createSheet("Hyperlinks");
|
||||||
|
|
||||||
|
//URL
|
||||||
|
cell = sheet.createRow(0).createCell((short)0);
|
||||||
|
cell.setCellValue("URL Link");
|
||||||
|
HSSFHyperlink link = new HSSFHyperlink(HSSFHyperlink.LINK_URL);
|
||||||
|
link.setAddress("http://poi.apache.org/");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
|
||||||
|
//link to a file in the current directory
|
||||||
|
cell = sheet.createRow(1).createCell((short)0);
|
||||||
|
cell.setCellValue("File Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_FILE);
|
||||||
|
link.setAddress("link1.xls");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
|
||||||
|
//e-mail link
|
||||||
|
cell = sheet.createRow(2).createCell((short)0);
|
||||||
|
cell.setCellValue("Email Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_EMAIL);
|
||||||
|
//note, if subject contains white spaces, make sure they are url-encoded
|
||||||
|
link.setAddress("mailto:poi@apache.org?subject=Hyperlinks");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
|
||||||
|
//link to a place in this workbook
|
||||||
|
|
||||||
|
//create a target sheet and cell
|
||||||
|
HSSFSheet sheet2 = wb.createSheet("Target Sheet");
|
||||||
|
sheet2.createRow(0).createCell((short)0).setCellValue("Target Cell");
|
||||||
|
|
||||||
|
cell = sheet.createRow(3).createCell((short)0);
|
||||||
|
cell.setCellValue("Worksheet Link");
|
||||||
|
link = new HSSFHyperlink(HSSFHyperlink.LINK_DOCUMENT);
|
||||||
|
link.setAddress("'Target Sheet'!A1");
|
||||||
|
cell.setHyperlink(link);
|
||||||
|
|
||||||
|
//serialize and read again
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
wb.write(out);
|
||||||
|
|
||||||
|
wb = new HSSFWorkbook(new ByteArrayInputStream(out.toByteArray()));
|
||||||
|
sheet = wb.getSheet("Hyperlinks");
|
||||||
|
cell = sheet.getRow(0).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("http://poi.apache.org/", link.getAddress());
|
||||||
|
|
||||||
|
cell = sheet.getRow(1).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("link1.xls", link.getAddress());
|
||||||
|
|
||||||
|
cell = sheet.getRow(2).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("mailto:poi@apache.org?subject=Hyperlinks", link.getAddress());
|
||||||
|
|
||||||
|
cell = sheet.getRow(3).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("'Target Sheet'!A1", link.getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCloneSheet() throws Exception {
|
||||||
|
FileInputStream is = new FileInputStream(new File(cwd, "HyperlinksOnManySheets.xls"));
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
HSSFCell cell;
|
||||||
|
HSSFHyperlink link;
|
||||||
|
|
||||||
|
HSSFSheet sheet = wb.cloneSheet(0);
|
||||||
|
|
||||||
|
cell = sheet.getRow(4).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("http://poi.apache.org/", link.getAddress());
|
||||||
|
|
||||||
|
cell = sheet.getRow(8).getCell((short)0);
|
||||||
|
link = cell.getHyperlink();
|
||||||
|
assertNotNull(link);
|
||||||
|
assertEquals("http://poi.apache.org/hssf/", link.getAddress());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user