1 | /* $Id$ $Name$ Copyright 2001, 2002 Paulo Soares The contents of this file are subject to the | |
2 | * Mozilla Public License Version 1.1 (the "License"); you may not use this file except in | |
3 | * compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ | |
4 | * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF | |
5 | * ANY KIND, either express or implied. See the License for the specific language governing rights | |
6 | * and limitations under the License. The Original Code is 'iText, a free JAVA-PDF library'. The | |
7 | * Initial Developer of the Original Code is Bruno Lowagie. Portions created by the Initial | |
8 | * Developer are Copyright (C) 1999, 2000, 2001, 2002 by Bruno Lowagie. All Rights Reserved. | |
9 | * Co-Developer of the code is Paulo Soares. Portions created by the Co-Developer are Copyright (C) | |
10 | * 2000, 2001, 2002 by Paulo Soares. All Rights Reserved. Contributor(s): all the names of the | |
11 | * contributors are added in the source code where applicable. Alternatively, the contents of this | |
12 | * file may be used under the terms of the LGPL license (the "GNU LIBRARY GENERAL PUBLIC LICENSE"), | |
13 | * in which case the provisions of LGPL are applicable instead of those above. If you wish to allow | |
14 | * use of your version of this file only under the terms of the LGPL License and not to allow others | |
15 | * to use your version of this file under the MPL, indicate your decision by deleting the provisions | |
16 | * above and replace them with the notice and other provisions required by the LGPL. If you do not | |
17 | * delete the provisions above, a recipient may use your version of this file under either the MPL | |
18 | * or the GNU LIBRARY GENERAL PUBLIC LICENSE. This library is free software; you can redistribute it | |
19 | * and/or modify it under the terms of the MPL as stated above or under the terms of the GNU Library | |
20 | * General Public License as published by the Free Software Foundation; either version 2 of the | |
21 | * License, or any later version. This library is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A | |
23 | * PARTICULAR PURPOSE. See the GNU Library general Public License for more details. If you didn't | |
24 | * download this code from the following link, you should check if you aren't using an obsolete | |
25 | * version: http://www.lowagie.com/iText/ */ | |
26 | ||
27 | package com.lowagie.text.pdf; | |
28 | ||
29 | ||
30 | import com.lowagie.text.error_messages.MessageLocalization; | |
31 | import com.lowagie.text.ExceptionConverter; | |
32 | import com.lowagie.text.factories.RomanAlphabetFactory; | |
33 | import com.lowagie.text.factories.RomanNumberFactory; | |
34 | ||
35 | import java.io.IOException; | |
36 | import java.util.Arrays; | |
37 | import java.util.HashMap; | |
38 | ||
39 | /** | |
40 | * Page labels are used to identify each page visually on the screen or in print. | |
41 | * | |
42 | * @author Paulo Soares (psoares@consiste.pt) | |
43 | */ | |
44 | public class PdfPageLabels { | |
45 | ||
46 | /** | |
47 | * Logical pages will have the form 1,2,3,... | |
48 | */ | |
49 | public static final int DECIMAL_ARABIC_NUMERALS = 0; | |
50 | ||
51 | /** | |
52 | * Logical pages will have the form I,II,III,IV,... | |
53 | */ | |
54 | public static final int UPPERCASE_ROMAN_NUMERALS = 1; | |
55 | ||
56 | /** | |
57 | * Logical pages will have the form i,ii,iii,iv,... | |
58 | */ | |
59 | public static final int LOWERCASE_ROMAN_NUMERALS = 2; | |
60 | ||
61 | /** | |
62 | * Logical pages will have the form of uppercase letters (A to Z for the first 26 pages, AA to | |
63 | * ZZ for the next 26, and so on) | |
64 | */ | |
65 | public static final int UPPERCASE_LETTERS = 3; | |
66 | ||
67 | /** | |
68 | * Logical pages will have the form of uppercase letters (a to z for the first 26 pages, aa to | |
69 | * zz for the next 26, and so on) | |
70 | */ | |
71 | public static final int LOWERCASE_LETTERS = 4; | |
72 | ||
73 | /** | |
74 | * No logical page numbers are generated but fixed text may still exist | |
75 | */ | |
76 | public static final int EMPTY = 5; | |
77 | ||
78 | /** | |
79 | * Dictionary values to set the logical page styles | |
80 | */ | |
81 | static PdfName[] numberingStyle = new PdfName[] | |
82 | { | |
83 | PdfName.D, PdfName.R, new PdfName("r"), PdfName.A, new PdfName("a") | |
84 | }; | |
85 | ||
86 | /** | |
87 | * The sequence of logical pages. Will contain at least a value for page 1 | |
88 | */ | |
89 | private HashMap map; | |
90 | ||
91 | /** | |
92 | * Creates a new PdfPageLabel with a default logical page 1 | |
93 | */ | |
94 | public PdfPageLabels() { | |
95 | map = new HashMap(); | |
96 |
1
1. |
addPageLabel(1, PdfPageLabels.DECIMAL_ARABIC_NUMERALS, null, 1); |
97 | } | |
98 | ||
99 | /** | |
100 | * Adds or replaces a page label. | |
101 | * | |
102 | * @param page | |
103 | * the real page to start the numbering. First page is 1 | |
104 | * @param numberStyle | |
105 | * the numbering style such as LOWERCASE_ROMAN_NUMERALS | |
106 | * @param text | |
107 | * the text to prefix the number. Can be <CODE>null</CODE> or empty | |
108 | * @param firstPage | |
109 | * the first logical page number | |
110 | */ | |
111 | public void addPageLabel(int page, int numberStyle, String text, int firstPage) { | |
112 |
4
1. addPageLabel : changed conditional boundary → NO_COVERAGE 2. addPageLabel : changed conditional boundary → NO_COVERAGE 3. addPageLabel : negated conditional → NO_COVERAGE 4. addPageLabel : negated conditional → NO_COVERAGE |
if (page < 1 || firstPage < 1) { |
113 | throw new IllegalArgumentException( | |
114 | MessageLocalization.getComposedMessage("in.a.page.label.the.page.numbers.must.be.greater.or.equal.to.1")); | |
115 | } | |
116 | PdfDictionary dic = new PdfDictionary(); | |
117 |
4
1. addPageLabel : changed conditional boundary → NO_COVERAGE 2. addPageLabel : changed conditional boundary → NO_COVERAGE 3. addPageLabel : negated conditional → NO_COVERAGE 4. addPageLabel : negated conditional → NO_COVERAGE |
if (numberStyle >= 0 && numberStyle < PdfPageLabels.numberingStyle.length) { |
118 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
dic.put(PdfName.S, PdfPageLabels.numberingStyle[numberStyle]); |
119 | } | |
120 |
1
1. addPageLabel : negated conditional → NO_COVERAGE |
if (text != null) { |
121 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
dic.put(PdfName.P, new PdfString(text, PdfObject.TEXT_UNICODE)); |
122 | } | |
123 |
1
1. addPageLabel : negated conditional → NO_COVERAGE |
if (firstPage != 1) { |
124 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfDictionary::put → NO_COVERAGE |
dic.put(PdfName.ST, new PdfNumber(firstPage)); |
125 | } | |
126 |
1
1. addPageLabel : Replaced integer subtraction with addition → NO_COVERAGE |
map.put(page - 1, dic); |
127 | } | |
128 | ||
129 | /** | |
130 | * Adds or replaces a page label. The first logical page has the default of 1. | |
131 | * | |
132 | * @param page | |
133 | * the real page to start the numbering. First page is 1 | |
134 | * @param numberStyle | |
135 | * the numbering style such as LOWERCASE_ROMAN_NUMERALS | |
136 | * @param text | |
137 | * the text to prefix the number. Can be <CODE>null</CODE> or empty | |
138 | */ | |
139 | public void addPageLabel(int page, int numberStyle, String text) { | |
140 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfPageLabels::addPageLabel → NO_COVERAGE |
addPageLabel(page, numberStyle, text, 1); |
141 | } | |
142 | ||
143 | /** | |
144 | * Adds or replaces a page label. There is no text prefix and the first logical page has the | |
145 | * default of 1. | |
146 | * | |
147 | * @param page | |
148 | * the real page to start the numbering. First page is 1 | |
149 | * @param numberStyle | |
150 | * the numbering style such as LOWERCASE_ROMAN_NUMERALS | |
151 | */ | |
152 | public void addPageLabel(int page, int numberStyle) { | |
153 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfPageLabels::addPageLabel → NO_COVERAGE |
addPageLabel(page, numberStyle, null, 1); |
154 | } | |
155 | ||
156 | /** | |
157 | * Adds or replaces a page label. | |
158 | */ | |
159 | public void addPageLabel(PdfPageLabelFormat format) { | |
160 |
1
1. addPageLabel : removed call to com/lowagie/text/pdf/PdfPageLabels::addPageLabel → NO_COVERAGE |
addPageLabel(format.physicalPage, format.numberStyle, format.prefix, format.logicalPage); |
161 | } | |
162 | ||
163 | /** | |
164 | * Removes a page label. The first page label can not be removed, only changed. | |
165 | * | |
166 | * @param page | |
167 | * the real page to remove | |
168 | */ | |
169 | public void removePageLabel(int page) { | |
170 |
2
1. removePageLabel : changed conditional boundary → NO_COVERAGE 2. removePageLabel : negated conditional → NO_COVERAGE |
if (page <= 1) { |
171 | return; | |
172 | } | |
173 |
1
1. removePageLabel : Replaced integer subtraction with addition → NO_COVERAGE |
map.remove(page - 1); |
174 | } | |
175 | ||
176 | /** | |
177 | * Gets the page label dictionary to insert into the document. | |
178 | * | |
179 | * @return the page label dictionary | |
180 | */ | |
181 | PdfDictionary getDictionary(PdfWriter writer) { | |
182 | try { | |
183 |
1
1. getDictionary : mutated return of Object value for com/lowagie/text/pdf/PdfPageLabels::getDictionary to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return PdfNumberTree.writeTree(map, writer); |
184 | } catch (IOException e) { | |
185 | throw new ExceptionConverter(e); | |
186 | } | |
187 | } | |
188 | ||
189 | /** | |
190 | * Retrieves the page labels from a PDF as an array of String objects. | |
191 | * | |
192 | * @param reader | |
193 | * a PdfReader object that has the page labels you want to retrieve | |
194 | * @return a String array or <code>null</code> if no page labels are present | |
195 | */ | |
196 | public static String[] getPageLabels(PdfReader reader) { | |
197 | ||
198 | int n = reader.getNumberOfPages(); | |
199 | ||
200 | PdfDictionary dict = reader.getCatalog(); | |
201 | PdfDictionary labels = (PdfDictionary) PdfReader.getPdfObjectRelease(dict.get(PdfName.PAGELABELS)); | |
202 |
1
1. getPageLabels : negated conditional → NO_COVERAGE |
if (labels == null) { |
203 |
1
1. getPageLabels : mutated return of Object value for com/lowagie/text/pdf/PdfPageLabels::getPageLabels to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return null; |
204 | } | |
205 | ||
206 | String[] labelstrings = new String[n]; | |
207 | ||
208 | HashMap numberTree = PdfNumberTree.readTree(labels); | |
209 | ||
210 | int pagecount = 1; | |
211 | Integer current; | |
212 | char type = 'D'; | |
213 | String prefix = ""; | |
214 |
3
1. getPageLabels : changed conditional boundary → NO_COVERAGE 2. getPageLabels : Changed increment from 1 to -1 → NO_COVERAGE 3. getPageLabels : negated conditional → NO_COVERAGE |
for (int i = 0; i < n; i++ ) { |
215 | current = i; | |
216 |
1
1. getPageLabels : negated conditional → NO_COVERAGE |
if (numberTree.containsKey(current)) { |
217 | PdfDictionary d = (PdfDictionary) PdfReader.getPdfObjectRelease((PdfObject) numberTree.get(current)); | |
218 |
1
1. getPageLabels : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.ST)) { |
219 | pagecount = ((PdfNumber) d.get(PdfName.ST)).intValue(); | |
220 | } else { | |
221 | pagecount = 1; | |
222 | } | |
223 |
1
1. getPageLabels : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.P)) { |
224 | prefix = ((PdfString) d.get(PdfName.P)).toUnicodeString(); | |
225 | } else { | |
226 | prefix = ""; | |
227 | } | |
228 |
1
1. getPageLabels : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.S)) { |
229 | type = d.get(PdfName.S).toString() | |
230 | .charAt(1); | |
231 | } | |
232 | } | |
233 | switch (type) { | |
234 | default: | |
235 | labelstrings[i] = prefix + pagecount; | |
236 | break; | |
237 | case 'R': | |
238 | labelstrings[i] = prefix + RomanNumberFactory.getUpperCaseString(pagecount); | |
239 | break; | |
240 | case 'r': | |
241 | labelstrings[i] = prefix + RomanNumberFactory.getLowerCaseString(pagecount); | |
242 | break; | |
243 | case 'A': | |
244 | labelstrings[i] = prefix + RomanAlphabetFactory.getUpperCaseString(pagecount); | |
245 | break; | |
246 | case 'a': | |
247 | labelstrings[i] = prefix + RomanAlphabetFactory.getLowerCaseString(pagecount); | |
248 | break; | |
249 | } | |
250 |
1
1. getPageLabels : Changed increment from 1 to -1 → NO_COVERAGE |
pagecount++ ; |
251 | } | |
252 |
1
1. getPageLabels : mutated return of Object value for com/lowagie/text/pdf/PdfPageLabels::getPageLabels to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return labelstrings; |
253 | } | |
254 | ||
255 | /** | |
256 | * Retrieves the page labels from a PDF as an array of {@link PdfPageLabelFormat} objects. | |
257 | * | |
258 | * @param reader | |
259 | * a PdfReader object that has the page labels you want to retrieve | |
260 | * @return a PdfPageLabelEntry array, containing an entry for each format change or | |
261 | * <code>null</code> if no page labels are present | |
262 | */ | |
263 | public static PdfPageLabelFormat[] getPageLabelFormats(PdfReader reader) { | |
264 | PdfDictionary dict = reader.getCatalog(); | |
265 | PdfDictionary labels = (PdfDictionary) PdfReader.getPdfObjectRelease(dict.get(PdfName.PAGELABELS)); | |
266 |
1
1. getPageLabelFormats : negated conditional → NO_COVERAGE |
if (labels == null) { |
267 |
1
1. getPageLabelFormats : mutated return of Object value for com/lowagie/text/pdf/PdfPageLabels::getPageLabelFormats to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return null; |
268 | } | |
269 | HashMap numberTree = PdfNumberTree.readTree(labels); | |
270 | Integer[] numbers = new Integer[numberTree.size()]; | |
271 | numbers = (Integer[]) numberTree.keySet() | |
272 | .toArray(numbers); | |
273 |
1
1. getPageLabelFormats : removed call to java/util/Arrays::sort → NO_COVERAGE |
Arrays.sort(numbers); |
274 | PdfPageLabelFormat[] formats = new PdfPageLabelFormat[numberTree.size()]; | |
275 | String prefix; | |
276 | int numberStyle; | |
277 | int pagecount; | |
278 |
3
1. getPageLabelFormats : changed conditional boundary → NO_COVERAGE 2. getPageLabelFormats : Changed increment from 1 to -1 → NO_COVERAGE 3. getPageLabelFormats : negated conditional → NO_COVERAGE |
for (int k = 0; k < numbers.length; ++k) { |
279 | Integer key = numbers[k]; | |
280 | PdfDictionary d = (PdfDictionary) PdfReader.getPdfObjectRelease((PdfObject) numberTree.get(key)); | |
281 |
1
1. getPageLabelFormats : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.ST)) { |
282 | pagecount = ((PdfNumber) d.get(PdfName.ST)).intValue(); | |
283 | } else { | |
284 | pagecount = 1; | |
285 | } | |
286 |
1
1. getPageLabelFormats : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.P)) { |
287 | prefix = ((PdfString) d.get(PdfName.P)).toUnicodeString(); | |
288 | } else { | |
289 | prefix = ""; | |
290 | } | |
291 |
1
1. getPageLabelFormats : negated conditional → NO_COVERAGE |
if (d.contains(PdfName.S)) { |
292 | char type = d.get(PdfName.S).toString() | |
293 | .charAt(1); | |
294 | switch (type) { | |
295 | case 'R': | |
296 | numberStyle = PdfPageLabels.UPPERCASE_ROMAN_NUMERALS; | |
297 | break; | |
298 | case 'r': | |
299 | numberStyle = PdfPageLabels.LOWERCASE_ROMAN_NUMERALS; | |
300 | break; | |
301 | case 'A': | |
302 | numberStyle = PdfPageLabels.UPPERCASE_LETTERS; | |
303 | break; | |
304 | case 'a': | |
305 | numberStyle = PdfPageLabels.LOWERCASE_LETTERS; | |
306 | break; | |
307 | default: | |
308 | numberStyle = PdfPageLabels.DECIMAL_ARABIC_NUMERALS; | |
309 | break; | |
310 | } | |
311 | } else { | |
312 | numberStyle = PdfPageLabels.EMPTY; | |
313 | } | |
314 |
1
1. getPageLabelFormats : Replaced integer addition with subtraction → NO_COVERAGE |
formats[k] = new PdfPageLabelFormat(key + 1, numberStyle, prefix, pagecount); |
315 | } | |
316 |
1
1. getPageLabelFormats : mutated return of Object value for com/lowagie/text/pdf/PdfPageLabels::getPageLabelFormats to ( if (x != null) null else throw new RuntimeException ) → NO_COVERAGE |
return formats; |
317 | } | |
318 | ||
319 | public static class PdfPageLabelFormat { | |
320 | ||
321 | public int physicalPage; | |
322 | ||
323 | public int numberStyle; | |
324 | ||
325 | public String prefix; | |
326 | ||
327 | public int logicalPage; | |
328 | ||
329 | /** | |
330 | * Creates a page label format. | |
331 | * | |
332 | * @param physicalPage | |
333 | * the real page to start the numbering. First page is 1 | |
334 | * @param numberStyle | |
335 | * the numbering style such as LOWERCASE_ROMAN_NUMERALS | |
336 | * @param prefix | |
337 | * the text to prefix the number. Can be <CODE>null</CODE> or empty | |
338 | * @param logicalPage | |
339 | * the first logical page number | |
340 | */ | |
341 | public PdfPageLabelFormat( int physicalPage, | |
342 | int numberStyle, | |
343 | String prefix, | |
344 | int logicalPage) { | |
345 | this.physicalPage = physicalPage; | |
346 | this.numberStyle = numberStyle; | |
347 | this.prefix = prefix; | |
348 | this.logicalPage = logicalPage; | |
349 | } | |
350 | } | |
351 | } | |
Mutations | ||
96 |
1.1 |
|
112 |
1.1 2.2 3.3 4.4 |
|
117 |
1.1 2.2 3.3 4.4 |
|
118 |
1.1 |
|
120 |
1.1 |
|
121 |
1.1 |
|
123 |
1.1 |
|
124 |
1.1 |
|
126 |
1.1 |
|
140 |
1.1 |
|
153 |
1.1 |
|
160 |
1.1 |
|
170 |
1.1 2.2 |
|
173 |
1.1 |
|
183 |
1.1 |
|
202 |
1.1 |
|
203 |
1.1 |
|
214 |
1.1 2.2 3.3 |
|
216 |
1.1 |
|
218 |
1.1 |
|
223 |
1.1 |
|
228 |
1.1 |
|
250 |
1.1 |
|
252 |
1.1 |
|
266 |
1.1 |
|
267 |
1.1 |
|
273 |
1.1 |
|
278 |
1.1 2.2 3.3 |
|
281 |
1.1 |
|
286 |
1.1 |
|
291 |
1.1 |
|
314 |
1.1 |
|
316 |
1.1 |