View | Details | Raw Unified | Return to bug 55904
Collapse All | Expand All

(-)src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFHyperlink.java (-16 / +43 lines)
Lines 23-28 Link Here
23
import org.apache.poi.openxml4j.opc.PackagePart;
23
import org.apache.poi.openxml4j.opc.PackagePart;
24
import org.apache.poi.openxml4j.opc.PackageRelationship;
24
import org.apache.poi.openxml4j.opc.PackageRelationship;
25
import org.apache.poi.ss.usermodel.Hyperlink;
25
import org.apache.poi.ss.usermodel.Hyperlink;
26
import org.apache.poi.ss.util.CellRangeAddress;
26
import org.apache.poi.ss.util.CellReference;
27
import org.apache.poi.ss.util.CellReference;
27
import org.apache.poi.util.Internal;
28
import org.apache.poi.util.Internal;
28
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
29
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
Lines 33-41 Link Here
33
 * are largely stored as relations of the sheet
34
 * are largely stored as relations of the sheet
34
 */
35
 */
35
public class XSSFHyperlink implements Hyperlink {
36
public class XSSFHyperlink implements Hyperlink {
36
    final private HyperlinkType _type;
37
    private final HyperlinkType _type;
37
    final private PackageRelationship _externalRel;
38
    private final PackageRelationship _externalRel;
38
    final private CTHyperlink _ctHyperlink; //contains a reference to the cell where the hyperlink is anchored, getRef()
39
    private final CTHyperlink _ctHyperlink; //contains a reference to the cell where the hyperlink is anchored, getRef()
40
    private CellRangeAddress _cellRef; //lazily cache a CellRangeAddress object of _ctHyperlink.getRef
39
    private String _location; //what the hyperlink refers to
41
    private String _location; //what the hyperlink refers to
40
42
41
    /**
43
    /**
Lines 134-139 Link Here
134
    }
136
    }
135
    /**
137
    /**
136
     * @return the underlying CTHyperlink object
138
     * @return the underlying CTHyperlink object
139
     * 
140
     * The CTHyperlink should not be modified by any class other than XSSFHyperlink.
137
     */
141
     */
138
    @Internal
142
    @Internal
139
    public CTHyperlink getCTHyperlink() {
143
    public CTHyperlink getCTHyperlink() {
Lines 287-304 Link Here
287
    @Internal
291
    @Internal
288
    public void setCellReference(String ref) {
292
    public void setCellReference(String ref) {
289
        _ctHyperlink.setRef(ref);
293
        _ctHyperlink.setRef(ref);
294
        _cellRef = null;
290
    }
295
    }
291
    @Internal
296
    @Internal
292
    protected void setCellReference(CellReference ref) {
297
    protected void setCellReference(CellReference ref) {
293
        setCellReference(ref.formatAsString());
298
        setCellReference(ref.formatAsString());
294
    }
299
    }
300
    @Internal
301
    protected void setCellReference(CellRangeAddress ref) {
302
        setCellReference(ref.formatAsString());
303
        //create a copy so that it cannot be modified outside of this class
304
        _cellRef = ref.copy();
305
    }
295
306
296
    private CellReference buildCellReference() {
307
    private CellRangeAddress getCellReference() {
297
        String ref = _ctHyperlink.getRef();
308
        if (_cellRef == null) {
298
        if (ref == null) {
309
            String ref = _ctHyperlink.getRef();
299
            ref = "A1";
310
            if (ref == null) {
311
                ref = "A1";
312
            }
313
            _cellRef = CellRangeAddress.valueOf(ref);
300
        }
314
        }
301
        return new CellReference(ref);
315
        // if this method were public, it would need to return a read-only CellRangeAddress or _cellRef.copy()
316
        return _cellRef;
302
    }
317
    }
303
318
304
319
Lines 309-315 Link Here
309
     */
324
     */
310
    @Override
325
    @Override
311
    public int getFirstColumn() {
326
    public int getFirstColumn() {
312
        return buildCellReference().getCol();
327
        return getCellReference().getFirstColumn();
313
    }
328
    }
314
329
315
330
Lines 320-326 Link Here
320
     */
335
     */
321
    @Override
336
    @Override
322
    public int getLastColumn() {
337
    public int getLastColumn() {
323
        return buildCellReference().getCol();
338
        return getCellReference().getLastColumn();
324
    }
339
    }
325
340
326
    /**
341
    /**
Lines 330-336 Link Here
330
     */
345
     */
331
    @Override
346
    @Override
332
    public int getFirstRow() {
347
    public int getFirstRow() {
333
        return buildCellReference().getRow();
348
        return getCellReference().getFirstRow();
334
    }
349
    }
335
350
336
351
Lines 341-347 Link Here
341
     */
356
     */
342
    @Override
357
    @Override
343
    public int getLastRow() {
358
    public int getLastRow() {
344
        return buildCellReference().getRow();
359
        return getCellReference().getLastRow();
345
    }
360
    }
346
361
347
    /**
362
    /**
Lines 351-357 Link Here
351
     */
366
     */
352
    @Override
367
    @Override
353
    public void setFirstColumn(int col) {
368
    public void setFirstColumn(int col) {
354
        setCellReference(new CellReference( getFirstRow(), col ));
369
        CellRangeAddress ref = getCellReference();
370
        // modify _cellRef in-place. If it was not modified in-place, _cellRef would need to be set to null.
371
        ref.setFirstColumn(col);
372
        _ctHyperlink.setRef(ref.formatAsString());
355
    }
373
    }
356
374
357
    /**
375
    /**
Lines 362-368 Link Here
362
     */
380
     */
363
    @Override
381
    @Override
364
    public void setLastColumn(int col) {
382
    public void setLastColumn(int col) {
365
        setFirstColumn(col);
383
        CellRangeAddress ref = getCellReference();
384
        // modify _cellRef in-place. If it was not modified in-place, _cellRef would need to be set to null.
385
        ref.setLastColumn(col);
386
        _ctHyperlink.setRef(ref.formatAsString());
366
    }
387
    }
367
388
368
    /**
389
    /**
Lines 372-378 Link Here
372
     */
393
     */
373
    @Override
394
    @Override
374
    public void setFirstRow(int row) {
395
    public void setFirstRow(int row) {
375
        setCellReference(new CellReference( row, getFirstColumn() ));
396
        CellRangeAddress ref = getCellReference();
397
        // modify _cellRef in-place. If it was not modified in-place, _cellRef would need to be set to null.
398
        ref.setFirstRow(row);
399
        _ctHyperlink.setRef(ref.formatAsString());
376
    }
400
    }
377
401
378
    /**
402
    /**
Lines 383-389 Link Here
383
     */
407
     */
384
    @Override
408
    @Override
385
    public void setLastRow(int row) {
409
    public void setLastRow(int row) {
386
        setFirstRow(row);
410
        CellRangeAddress ref = getCellReference();
411
        // modify _cellRef in-place. If it was not modified in-place, _cellRef would need to be set to null.
412
        ref.setLastRow(row);
413
        _ctHyperlink.setRef(ref.formatAsString());
387
	}
414
	}
388
415
389
    /**
416
    /**
(-)src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java (-2 / +16 lines)
Lines 819-829 Link Here
819
     */
819
     */
820
    @Override
820
    @Override
821
    public XSSFHyperlink getHyperlink(CellAddress addr) {
821
    public XSSFHyperlink getHyperlink(CellAddress addr) {
822
        String ref = addr.formatAsString();
822
        // find single-cell hyperlink at addr
823
        final String ref = addr.formatAsString();
824
        final int row = addr.getRow();
825
        final int column = addr.getColumn();
823
        for(XSSFHyperlink hyperlink : hyperlinks) {
826
        for(XSSFHyperlink hyperlink : hyperlinks) {
824
            if(hyperlink.getCellRef().equals(ref)) {
827
            final String hyperRef = hyperlink.getCellRef();
828
            
829
            // check if single-cell hyperlink
830
            if (hyperRef.equals(ref)) {
825
                return hyperlink;
831
                return hyperlink;
826
            }
832
            }
833
            
834
            // check if multi-cell hyperlink
835
            else if (hyperRef.contains(":")) {
836
                final CellRangeAddress area = CellRangeAddress.valueOf(hyperRef);
837
                if (area.isInRange(row, column)) {
838
                    return hyperlink;
839
                }
840
            }
827
        }
841
        }
828
        return null;
842
        return null;
829
    }
843
    }
(-)src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestCreateMultiCellHyperlink.java (+160 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.xssf.usermodel;
19
20
import static org.junit.Assert.assertEquals;
21
import static org.junit.Assert.assertNotNull;
22
23
import java.io.IOException;
24
25
import org.apache.poi.common.usermodel.HyperlinkType;
26
import org.apache.poi.ss.usermodel.Row;
27
import org.apache.poi.ss.util.CellAddress;
28
import org.apache.poi.ss.util.CellRangeAddress;
29
import org.apache.poi.xssf.XSSFTestDataSamples;
30
import org.junit.After;
31
import org.junit.Before;
32
import org.junit.Test;
33
34
/**
35
 * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=56527">bug 56527</a>
36
 * @throws Exception
37
 */
38
public class TestCreateMultiCellHyperlink {
39
40
    private static final String URL = "http://www.multicell.com/";
41
42
    // multi-cell hyperlink 2x3 B3:D4
43
    final CellRangeAddress B3_D4 = CellRangeAddress.valueOf("B3:D4");
44
    final int firstRow = B3_D4.getFirstRow();
45
    final int firstCol = B3_D4.getFirstColumn();
46
    final int lastRow = B3_D4.getLastRow();
47
    final int lastCol = B3_D4.getLastColumn();
48
    
49
    private XSSFWorkbook wb;
50
    private XSSFSheet sheet;
51
    private XSSFHyperlink hyperlink;
52
        
53
    @Before
54
    public void setUp() {
55
        wb = new XSSFWorkbook();
56
        sheet = wb.createSheet();
57
            
58
        // Create a 5x3 cell range (A1:E5) for a multi-cell hyperlink
59
        for (int r = 0; r < 5; r++) {
60
            Row row = sheet.createRow(r);
61
            for (int c = 1; c < 5; c++) {
62
                row.createCell(c);
63
            }
64
        }
65
66
        XSSFCreationHelper creationHelper = wb.getCreationHelper();
67
        hyperlink = creationHelper.createHyperlink(HyperlinkType.URL);
68
        hyperlink.setAddress(URL);
69
        sheet.addHyperlink(hyperlink);
70
    }
71
    
72
    @After
73
    public void tearDown() throws IOException {
74
        wb.close();
75
    }
76
    
77
    public void writeOutAndReadBack() throws IOException {
78
        XSSFWorkbook wb2 = XSSFTestDataSamples.writeOutAndReadBack(wb);
79
        wb.close();
80
        wb = wb2;
81
        sheet = wb.getSheetAt(0);
82
        hyperlink = sheet.getHyperlinkList().get(0);
83
    }
84
    
85
    @Test
86
    public void testCreateMuliCellHyperlink1() throws IOException {
87
        hyperlink.setFirstRow(firstRow);
88
        hyperlink.setFirstColumn(firstCol);
89
        hyperlink.setLastRow(lastRow);
90
        hyperlink.setLastColumn(lastCol);
91
        hyperlink.setAddress(URL);
92
        
93
        doChecks();
94
        writeOutAndReadBack();
95
        doChecks();
96
    }
97
    
98
    @Test
99
    public void testCreateMuliCellHyperlink2() throws IOException {
100
        hyperlink.setFirstColumn(firstCol);
101
        hyperlink.setFirstRow(firstRow);
102
        hyperlink.setLastColumn(lastCol);
103
        hyperlink.setLastRow(lastRow);
104
        
105
        doChecks();
106
        writeOutAndReadBack();
107
        doChecks();
108
    }
109
110
    @Test
111
    public void testCreateMuliCellHyperlink3() throws IOException {
112
        hyperlink.setLastRow(lastRow);
113
        hyperlink.setLastColumn(lastCol);
114
        hyperlink.setFirstRow(firstRow);
115
        hyperlink.setFirstColumn(firstCol);
116
117
        doChecks();
118
        writeOutAndReadBack();
119
        doChecks();
120
    }
121
    
122
    @Test
123
    public void testCreateMuliCellHyperlink4() throws IOException {
124
        hyperlink.setLastColumn(lastCol);
125
        hyperlink.setLastRow(lastRow);
126
        hyperlink.setFirstColumn(firstCol);
127
        hyperlink.setFirstRow(firstRow);
128
129
        doChecks();
130
        writeOutAndReadBack();
131
        doChecks();
132
    }
133
134
    
135
    private void doChecks() {
136
        for (int r = firstRow; r <= lastRow; r++) {
137
            XSSFRow row = sheet.getRow(r);
138
            for(int c = firstCol; c <= lastCol; c++) {
139
                CellAddress addr = new CellAddress(r, c);
140
                XSSFCell cell = row.getCell(c);
141
                XSSFHyperlink hyp = cell.getHyperlink();
142
                assertNotNull("Expected hyperlink in " + addr, hyp);
143
                
144
                assertEquals("B3:D4", hyp.getCellRef());
145
                
146
                // Check the methods getFistRow(), getFirstColumn(), getLastRow(), getLastColumn()
147
                assertEquals(firstRow, hyperlink.getFirstRow());
148
                assertEquals(firstCol, hyperlink.getFirstColumn());
149
                assertEquals(lastRow, hyperlink.getLastRow());
150
                assertEquals(lastCol, hyperlink.getLastColumn());
151
                                
152
                assertEquals(URL, hyp.getAddress());
153
                
154
                // cell.getHyperlink() and sheet.getHyperlink(CellAddress) should return the same hyperlink
155
                assertEquals(hyperlink, sheet.getHyperlink(addr));
156
            }
157
        }
158
    }
159
}
160
native
(-)src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestMultiCellHyperlink.java (+109 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.xssf.usermodel;
19
20
import static org.junit.Assert.assertEquals;
21
import static org.junit.Assert.assertNotNull;
22
import static org.junit.Assert.assertNull;
23
24
import org.apache.poi.ss.usermodel.Cell;
25
import org.apache.poi.ss.usermodel.Hyperlink;
26
import org.apache.poi.ss.usermodel.Row;
27
import org.apache.poi.ss.usermodel.Sheet;
28
import org.apache.poi.ss.util.CellAddress;
29
import org.apache.poi.ss.util.CellRangeAddress;
30
import org.apache.poi.xssf.XSSFTestDataSamples;
31
import org.junit.Test;
32
33
/**
34
 * @see <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=55904">bug 55904</a>
35
 * @throws Exception
36
 */
37
public class TestMultiCellHyperlink {
38
    
39
    private static final String URL = "http://www.multicell.com/";
40
    
41
    @Test
42
    public void testGetHyperlink() throws Exception {
43
        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("MultiCellHyperlink.xlsx");
44
        Sheet sheet = wb.getSheetAt(0);
45
        // single-cell hyperlink
46
        Cell cell = sheet.getRow(6).getCell(1); //B7
47
        Hyperlink hyperlink = cell.getHyperlink();
48
        
49
        // Check the methods getFistRow(), getFirstColumn(), getLastRow(), getLastColumn()
50
        assertEquals(6, hyperlink.getFirstRow());
51
        assertEquals(1, hyperlink.getFirstColumn());
52
        assertEquals(6, hyperlink.getLastRow());
53
        assertEquals(1, hyperlink.getLastColumn());
54
        
55
        assertNotNull(hyperlink);
56
        assertEquals("http://www.singlecell.com/", hyperlink.getAddress());
57
        
58
        // multi-cell hyperlink 2x3 B3:D4
59
        final CellRangeAddress B3_D4 = CellRangeAddress.valueOf("B3:D4");
60
        final int firstRow = B3_D4.getFirstRow();
61
        final int firstCol = B3_D4.getFirstColumn();
62
        final int lastRow = B3_D4.getLastRow();
63
        final int lastCol = B3_D4.getLastColumn();
64
        
65
        for (int r = firstRow; r <= lastRow; r++) {
66
            Row row = sheet.getRow(r);
67
            for(int c = firstCol; c <= lastCol; c++) {
68
                final CellAddress addr = new CellAddress(r, c);
69
                
70
                cell = row.getCell(c);
71
                hyperlink = cell.getHyperlink();
72
                assertNotNull("Expected hyperlink in " + addr, hyperlink);
73
                
74
                // Check the methods getFistRow(), getFirstColumn(), getLastRow(), getLastColumn()
75
                assertEquals(firstRow, hyperlink.getFirstRow());
76
                assertEquals(firstCol, hyperlink.getFirstColumn());
77
                assertEquals(lastRow, hyperlink.getLastRow());
78
                assertEquals(lastCol, hyperlink.getLastColumn());
79
                
80
                assertEquals(URL, hyperlink.getAddress());
81
                
82
                // cell.getHyperlink() and sheet.getHyperlink(CellAddress) should return the same hyperlink
83
                assertEquals(hyperlink, sheet.getHyperlink(addr));
84
            }
85
        }
86
        
87
        // Test cells that do not have hyperlinks
88
        checkNull(sheet, firstRow - 1, firstCol);
89
        checkNull(sheet, firstRow, firstCol - 1);
90
        checkNull(sheet,  lastRow + 1, lastCol);
91
        checkNull(sheet,  lastRow, lastCol + 1);
92
        
93
        wb.close();
94
    }
95
    
96
    private static void checkNull(Sheet sheet, int row, int col) {
97
        Row r = sheet.getRow(row);
98
        if (r == null) {
99
            r = sheet.createRow(row);
100
        }
101
        Cell cell = r.getCell(col);
102
        if (cell == null) {
103
            cell = r.createCell(col);
104
        }
105
        Hyperlink hyperlink = cell.getHyperlink();
106
        assertNull(hyperlink);
107
    }       
108
}
109
native
(-)src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java (+2 lines)
Lines 1856-1862 Link Here
1856
        sheet.addHyperlink(hyperlink);
1856
        sheet.addHyperlink(hyperlink);
1857
        hyperlink.setAddress("http://myurl");
1857
        hyperlink.setAddress("http://myurl");
1858
        hyperlink.setFirstRow(5);
1858
        hyperlink.setFirstRow(5);
1859
        hyperlink.setLastRow(5);
1859
        hyperlink.setFirstColumn(3);
1860
        hyperlink.setFirstColumn(3);
1861
        hyperlink.setLastColumn(3);
1860
1862
1861
        assertEquals(5, hyperlink.getFirstRow());
1863
        assertEquals(5, hyperlink.getFirstRow());
1862
        assertEquals(3, hyperlink.getFirstColumn());
1864
        assertEquals(3, hyperlink.getFirstColumn());

Return to bug 55904