aboutsummaryrefslogtreecommitdiffstats
path: root/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFHyperlink.java
blob: b3c4a7d48c602635ae46e8ba8e7d14525cc039ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/* ====================================================================
   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.xssf.usermodel;

import java.net.URI;
import java.net.URISyntaxException;

import org.apache.poi.common.usermodel.HyperlinkType;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.poi.openxml4j.opc.PackageRelationship;
import org.apache.poi.ss.usermodel.Hyperlink;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.util.Internal;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;

/**
 * XSSF Implementation of a Hyperlink.
 * Note - unlike with HSSF, many kinds of hyperlink
 * are largely stored as relations of the sheet
 */
public class XSSFHyperlink implements Hyperlink {
    final private HyperlinkType _type;
    final private PackageRelationship _externalRel;
    final private CTHyperlink _ctHyperlink; //contains a reference to the cell where the hyperlink is anchored, getRef()
    private String _location; //what the hyperlink refers to

    /**
     * Create a new XSSFHyperlink. This method is protected to be used only by {@link XSSFCreationHelper#createHyperlink(int)}
     *
     * @param type - the type of hyperlink to create, see {@link Hyperlink}
     * @deprecated POI 3.15 beta 3. Use {@link #XSSFHyperlink(Hyperlink)} instead.
     */
    protected XSSFHyperlink(int type) {
        this(HyperlinkType.forInt(type));
    }
    
    /**
     * Create a new XSSFHyperlink. This method is protected to be used only by {@link XSSFCreationHelper#createHyperlink(int)}
     *
     * @param type - the type of hyperlink to create, see {@link Hyperlink}
     */
    protected XSSFHyperlink(HyperlinkType type) {
        _type = type;
        _ctHyperlink = CTHyperlink.Factory.newInstance();
        _externalRel = null;
    }

    /**
     * Create a XSSFHyperlink and initialize it from the supplied CTHyperlink bean and package relationship
     *
     * @param ctHyperlink the xml bean containing xml properties
     * @param hyperlinkRel the relationship in the underlying OPC package which stores the actual link's address
     */
    protected XSSFHyperlink(CTHyperlink ctHyperlink, PackageRelationship hyperlinkRel) {
        _ctHyperlink = ctHyperlink;
        _externalRel = hyperlinkRel;

        // Figure out the Hyperlink type and destination

        if (_externalRel == null) {
            // If it has a location, it's internal
            if (ctHyperlink.getLocation() != null) {
                _type = HyperlinkType.DOCUMENT;
                _location = ctHyperlink.getLocation();
            } else if (ctHyperlink.getId() != null) {
                throw new IllegalStateException("The hyperlink for cell "
                        + ctHyperlink.getRef() + " references relation "
                        + ctHyperlink.getId() + ", but that didn't exist!");
            } else {
                // hyperlink is internal and is not related to other parts
                _type = HyperlinkType.DOCUMENT;
            }
        } else {
            URI target = _externalRel.getTargetURI();
            _location = target.toString();
            if (ctHyperlink.getLocation() != null) {
                // URI fragment
                _location += "#" + ctHyperlink.getLocation();
            }

            // Try to figure out the type
               if (_location.startsWith("http://") || _location.startsWith("https://")
                    || _location.startsWith("ftp://")) {
                _type = HyperlinkType.URL;
            } else if (_location.startsWith("mailto:")) {
                _type = HyperlinkType.EMAIL;
            } else {
                _type = HyperlinkType.FILE;
            }
        }

     }

    /**
     * Create a new XSSFHyperlink. This method is for Internal use only.
     * XSSFHyperlinks can be created by {@link XSSFCreationHelper}.
     * See the <a href="https://poi.apache.org/spreadsheet/quick-guide.html#Hyperlinks">spreadsheet quick-guide</a>
     * for an example.
     *
     * @param other the hyperlink to copy
     */
    @Internal //FIXME: change to protected if/when SXSSFHyperlink class is created
    public XSSFHyperlink(Hyperlink other) {
        if (other instanceof XSSFHyperlink) {
            XSSFHyperlink xlink = (XSSFHyperlink) other;
            _type = xlink.getTypeEnum();
            _location = xlink._location;
            _externalRel = xlink._externalRel;
            _ctHyperlink = (CTHyperlink) xlink._ctHyperlink.copy();
        }
        else {
            _type = other.getTypeEnum();
            _location = other.getAddress();
            _externalRel = null;
            _ctHyperlink = CTHyperlink.Factory.newInstance();
            setCellReference(new CellReference(other.getFirstRow(), other.getFirstColumn()));
        }
    }
    /**
     * @return the underlying CTHyperlink object
     */
    @Internal
    public CTHyperlink getCTHyperlink() {
        return _ctHyperlink;
    }

    /**
     * Do we need to a relation too, to represent
     * this hyperlink?
     */
    public boolean needsRelationToo() {
        return (_type != HyperlinkType.DOCUMENT);
    }

    /**
     * Generates the relation if required
     */
    protected void generateRelationIfNeeded(PackagePart sheetPart) {
        if (_externalRel == null && needsRelationToo()) {
            // Generate the relation
            PackageRelationship rel =
                    sheetPart.addExternalRelationship(_location, XSSFRelation.SHEET_HYPERLINKS.getRelation());

            // Update the r:id
            _ctHyperlink.setId(rel.getId());
        }
    }

    /**
     * Return the type of this hyperlink
     *
     * @return the type of this hyperlink
     * @see HyperlinkType#forInt
     * @deprecated POI 3.15 beta 3. Use {@link #getTypeEnum()} instead.
     */
    @Override
    public int getType() {
        return _type.getCode();
    }
    
    /**
     * Return the type of this hyperlink
     *
     * @return the type of this hyperlink
     */
    @Override
    public HyperlinkType getTypeEnum() {
        return _type;
    }

    /**
     * Get the reference of the cell this applies to,
     * es A55
     */
    public String getCellRef() {
        return _ctHyperlink.getRef();
    }

    /**
     * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file.
     * The is the hyperlink target.
     *
     * @return the address of this hyperlink
     */
    @Override
    public String getAddress() {
        return _location;
    }

    /**
     * Return text label for this hyperlink
     *
     * @return text to display
     */
    @Override
    public String getLabel() {
        return _ctHyperlink.getDisplay();
    }

    /**
     * Location within target. If target is a workbook (or this workbook) this shall refer to a
     * sheet and cell or a defined name. Can also be an HTML anchor if target is HTML file.
     *
     * @return location
     */
    public String getLocation() {
        return _ctHyperlink.getLocation();
    }

    /**
     * Sets text label for this hyperlink
     *
     * @param label text label for this hyperlink
     */
    @Override
    public void setLabel(String label) {
        _ctHyperlink.setDisplay(label);
    }

    /**
     * Location within target. If target is a workbook (or this workbook) this shall refer to a
     * sheet and cell or a defined name. Can also be an HTML anchor if target is HTML file.
     *
     * @param location - string representing a location of this hyperlink
     */
    public void setLocation(String location) {
        _ctHyperlink.setLocation(location);
    }

    /**
     * Hyperlink address. Depending on the hyperlink type it can be URL, e-mail, path to a file
     * This is the hyperlink target.
     *
     * @param address - the address of this hyperlink
     */
    @Override
    public void setAddress(String address) {
        validate(address);

       _location = address;
        //we must set location for internal hyperlinks
        if (_type == HyperlinkType.DOCUMENT) {
            setLocation(address);
        }
    }

    @SuppressWarnings("fall-through")
    private void validate(String address) {
        switch (_type) {
            // email, path to file and url must be valid URIs
            case EMAIL:
            case FILE:
            case URL:
                try {
                    new URI(address);
                } catch (URISyntaxException e) {
                    throw new IllegalArgumentException("Address of hyperlink must be a valid URI", e);
                }
                break;
            case DOCUMENT:
                // currently not evaluating anything.
                break;
            default:
                throw new IllegalStateException("Invalid Hyperlink type: " + _type);
        }
    }

    /**
     * Assigns this hyperlink to the given cell reference
     */
    @Internal
    public void setCellReference(String ref) {
        _ctHyperlink.setRef(ref);
    }
    @Internal
    protected void setCellReference(CellReference ref) {
        setCellReference(ref.formatAsString());
    }

    private CellReference buildCellReference() {
        String ref = _ctHyperlink.getRef();
        if (ref == null) {
            ref = "A1";
        }
        return new CellReference(ref);
    }


    /**
     * Return the column of the first cell that contains the hyperlink
     *
     * @return the 0-based column of the first cell that contains the hyperlink
     */
    @Override
    public int getFirstColumn() {
        return buildCellReference().getCol();
    }


    /**
     * Return the column of the last cell that contains the hyperlink
     *
     * @return the 0-based column of the last cell that contains the hyperlink
     */
    @Override
    public int getLastColumn() {
        return buildCellReference().getCol();
    }

    /**
     * Return the row of the first cell that contains the hyperlink
     *
     * @return the 0-based row of the cell that contains the hyperlink
     */
    @Override
    public int getFirstRow() {
        return buildCellReference().getRow();
    }


    /**
     * Return the row of the last cell that contains the hyperlink
     *
     * @return the 0-based row of the last cell that contains the hyperlink
     */
    @Override
    public int getLastRow() {
        return buildCellReference().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
     */
    @Override
    public void setFirstColumn(int col) {
        setCellReference(new CellReference( getFirstRow(), col ));
    }

    /**
     * Set the column of the last cell that contains the hyperlink.
     * For XSSF, a Hyperlink may only reference one cell
     *
     * @param col the 0-based column of the last cell that contains the hyperlink
     */
    @Override
    public void setLastColumn(int col) {
        setFirstColumn(col);
    }

    /**
     * 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
     */
    @Override
    public void setFirstRow(int row) {
        setCellReference(new CellReference( row, getFirstColumn() ));
    }

    /**
     * Set the row of the last cell that contains the hyperlink.
     * For XSSF, a Hyperlink may only reference one cell
     *
     * @param row the 0-based row of the last cell that contains the hyperlink
     */
    @Override
    public void setLastRow(int row) {
        setFirstRow(row);
	}

    /**
     * @return additional text to help the user understand more about the hyperlink
     */
    public String getTooltip() {
        return _ctHyperlink.getTooltip();
    }

    /**
     * @param text  additional text to help the user understand more about the hyperlink
     */
    public void setTooltip(String text) {
        _ctHyperlink.setTooltip(text);
    }
}