001/* 002 * $Id: IndexEvents.java 4784 2011-03-15 08:33:00Z blowagie $ 003 * 004 * This file is part of the iText (R) project. 005 * Copyright (c) 1998-2011 1T3XT BVBA 006 * Authors: Bruno Lowagie, Paulo Soares, et al. 007 * 008 * This program is free software; you can redistribute it and/or modify 009 * it under the terms of the GNU Affero General Public License version 3 010 * as published by the Free Software Foundation with the addition of the 011 * following permission added to Section 15 as permitted in Section 7(a): 012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT, 013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. 014 * 015 * This program is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 017 * or FITNESS FOR A PARTICULAR PURPOSE. 018 * See the GNU Affero General Public License for more details. 019 * You should have received a copy of the GNU Affero General Public License 020 * along with this program; if not, see http://www.gnu.org/licenses or write to 021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 022 * Boston, MA, 02110-1301 USA, or download the license from the following URL: 023 * http://itextpdf.com/terms-of-use/ 024 * 025 * The interactive user interfaces in modified source and object code versions 026 * of this program must display Appropriate Legal Notices, as required under 027 * Section 5 of the GNU Affero General Public License. 028 * 029 * In accordance with Section 7(b) of the GNU Affero General Public License, 030 * a covered work must retain the producer line in every PDF that is created 031 * or manipulated using iText. 032 * 033 * You can be released from the requirements of the license by purchasing 034 * a commercial license. Buying such a license is mandatory as soon as you 035 * develop commercial activities involving the iText software without 036 * disclosing the source code of your own applications. 037 * These activities include: offering paid services to customers as an ASP, 038 * serving PDFs on the fly in a web application, shipping iText with a closed 039 * source product. 040 * 041 * For more information, please contact iText Software Corp. at this 042 * address: sales@itextpdf.com 043 */ 044package com.itextpdf.text.pdf.events; 045 046import java.util.ArrayList; 047import java.util.Collections; 048import java.util.Comparator; 049import java.util.HashMap; 050import java.util.List; 051import java.util.Map; 052import java.util.TreeMap; 053 054import com.itextpdf.text.Chunk; 055import com.itextpdf.text.Document; 056import com.itextpdf.text.Rectangle; 057import com.itextpdf.text.pdf.PdfPageEventHelper; 058import com.itextpdf.text.pdf.PdfWriter; 059 060/** 061 * Class for an index. 062 * 063 * @author Michael Niedermair 064 */ 065public class IndexEvents extends PdfPageEventHelper { 066 067 /** 068 * keeps the indextag with the pagenumber 069 */ 070 private Map<String, Integer> indextag = new TreeMap<String, Integer>(); 071 072 /** 073 * All the text that is passed to this event, gets registered in the indexentry. 074 * 075 * @see com.itextpdf.text.pdf.PdfPageEventHelper#onGenericTag( 076 * com.itextpdf.text.pdf.PdfWriter, com.itextpdf.text.Document, 077 * com.itextpdf.text.Rectangle, java.lang.String) 078 */ 079 @Override 080 public void onGenericTag(PdfWriter writer, Document document, 081 Rectangle rect, String text) { 082 indextag.put(text, Integer.valueOf(writer.getPageNumber())); 083 } 084 085 // -------------------------------------------------------------------- 086 /** 087 * indexcounter 088 */ 089 private long indexcounter = 0; 090 091 /** 092 * the list for the index entry 093 */ 094 private List<Entry> indexentry = new ArrayList<Entry>(); 095 096 /** 097 * Create an index entry. 098 * 099 * @param text The text for the Chunk. 100 * @param in1 The first level. 101 * @param in2 The second level. 102 * @param in3 The third level. 103 * @return Returns the Chunk. 104 */ 105 public Chunk create(final String text, final String in1, final String in2, 106 final String in3) { 107 108 Chunk chunk = new Chunk(text); 109 String tag = "idx_" + indexcounter++; 110 chunk.setGenericTag(tag); 111 chunk.setLocalDestination(tag); 112 Entry entry = new Entry(in1, in2, in3, tag); 113 indexentry.add(entry); 114 return chunk; 115 } 116 117 /** 118 * Create an index entry. 119 * 120 * @param text The text for the Chunk. 121 * @param in1 The first level. 122 * @return Returns the Chunk. 123 */ 124 public Chunk create(final String text, final String in1) { 125 return create(text, in1, "", ""); 126 } 127 128 /** 129 * Create an index entry. 130 * 131 * @param text The text for the Chunk. 132 * @param in1 The first level. 133 * @param in2 The second level. 134 * @return Returns the Chunk. 135 */ 136 public Chunk create(final String text, final String in1, final String in2) { 137 return create(text, in1, in2, ""); 138 } 139 140 /** 141 * Create an index entry. 142 * 143 * @param text The text. 144 * @param in1 The first level. 145 * @param in2 The second level. 146 * @param in3 The third level. 147 */ 148 public void create(final Chunk text, final String in1, final String in2, 149 final String in3) { 150 151 String tag = "idx_" + indexcounter++; 152 text.setGenericTag(tag); 153 text.setLocalDestination(tag); 154 Entry entry = new Entry(in1, in2, in3, tag); 155 indexentry.add(entry); 156 } 157 158 /** 159 * Create an index entry. 160 * 161 * @param text The text. 162 * @param in1 The first level. 163 */ 164 public void create(final Chunk text, final String in1) { 165 create(text, in1, "", ""); 166 } 167 168 /** 169 * Create an index entry. 170 * 171 * @param text The text. 172 * @param in1 The first level. 173 * @param in2 The second level. 174 */ 175 public void create(final Chunk text, final String in1, final String in2) { 176 create(text, in1, in2, ""); 177 } 178 179 /** 180 * Comparator for sorting the index 181 */ 182 private Comparator<Entry> comparator = new Comparator<Entry>() { 183 184 public int compare(Entry en1, Entry en2) { 185 int rt = 0; 186 if (en1.getIn1() != null && en2.getIn1() != null) { 187 if ((rt = en1.getIn1().compareToIgnoreCase(en2.getIn1())) == 0) { 188 // in1 equals 189 if (en1.getIn2() != null && en2.getIn2() != null) { 190 if ((rt = en1.getIn2() 191 .compareToIgnoreCase(en2.getIn2())) == 0) { 192 // in2 equals 193 if (en1.getIn3() != null && en2.getIn3() != null) { 194 rt = en1.getIn3().compareToIgnoreCase( 195 en2.getIn3()); 196 } 197 } 198 } 199 } 200 } 201 return rt; 202 } 203 }; 204 205 /** 206 * Set the comparator. 207 * @param aComparator The comparator to set. 208 */ 209 public void setComparator(Comparator<Entry> aComparator) { 210 comparator = aComparator; 211 } 212 213 /** 214 * Returns the sorted list with the entries and the collected page numbers. 215 * @return Returns the sorted list with the entries and the collected page numbers. 216 */ 217 public List<Entry> getSortedEntries() { 218 219 Map<String, Entry> grouped = new HashMap<String, Entry>(); 220 221 for (int i = 0; i < indexentry.size(); i++) { 222 Entry e = indexentry.get(i); 223 String key = e.getKey(); 224 225 Entry master = grouped.get(key); 226 if (master != null) { 227 master.addPageNumberAndTag(e.getPageNumber(), e.getTag()); 228 } else { 229 e.addPageNumberAndTag(e.getPageNumber(), e.getTag()); 230 grouped.put(key, e); 231 } 232 } 233 234 // copy to a list and sort it 235 List<Entry> sorted = new ArrayList<Entry>(grouped.values()); 236 Collections.sort(sorted, comparator); 237 return sorted; 238 } 239 240 // -------------------------------------------------------------------- 241 /** 242 * Class for an index entry. 243 * <p> 244 * In the first step, only in1, in2,in3 and tag are used. 245 * After the collections of the index entries, pagenumbers are used. 246 * </p> 247 */ 248 public class Entry { 249 250 /** 251 * first level 252 */ 253 private String in1; 254 255 /** 256 * second level 257 */ 258 private String in2; 259 260 /** 261 * third level 262 */ 263 private String in3; 264 265 /** 266 * the tag 267 */ 268 private String tag; 269 270 /** 271 * the list of all page numbers. 272 */ 273 private List<Integer> pagenumbers = new ArrayList<Integer>(); 274 275 /** 276 * the list of all tags. 277 */ 278 private List<String> tags = new ArrayList<String>(); 279 280 /** 281 * Create a new object. 282 * @param aIn1 The first level. 283 * @param aIn2 The second level. 284 * @param aIn3 The third level. 285 * @param aTag The tag. 286 */ 287 public Entry(final String aIn1, final String aIn2, final String aIn3, 288 final String aTag) { 289 in1 = aIn1; 290 in2 = aIn2; 291 in3 = aIn3; 292 tag = aTag; 293 } 294 295 /** 296 * Returns the in1. 297 * @return Returns the in1. 298 */ 299 public String getIn1() { 300 return in1; 301 } 302 303 /** 304 * Returns the in2. 305 * @return Returns the in2. 306 */ 307 public String getIn2() { 308 return in2; 309 } 310 311 /** 312 * Returns the in3. 313 * @return Returns the in3. 314 */ 315 public String getIn3() { 316 return in3; 317 } 318 319 /** 320 * Returns the tag. 321 * @return Returns the tag. 322 */ 323 public String getTag() { 324 return tag; 325 } 326 327 /** 328 * Returns the pagenumber for this entry. 329 * @return Returns the pagenumber for this entry. 330 */ 331 public int getPageNumber() { 332 int rt = -1; 333 Integer i = indextag.get(tag); 334 if (i != null) { 335 rt = i.intValue(); 336 } 337 return rt; 338 } 339 340 /** 341 * Add a pagenumber. 342 * @param number The page number. 343 * @param tag 344 */ 345 public void addPageNumberAndTag(final int number, final String tag) { 346 pagenumbers.add(Integer.valueOf(number)); 347 tags.add(tag); 348 } 349 350 /** 351 * Returns the key for the map-entry. 352 * @return Returns the key for the map-entry. 353 */ 354 public String getKey() { 355 return in1 + "!" + in2 + "!" + in3; 356 } 357 358 /** 359 * Returns the pagenumbers. 360 * @return Returns the pagenumbers. 361 */ 362 public List<Integer> getPagenumbers() { 363 return pagenumbers; 364 } 365 366 /** 367 * Returns the tags. 368 * @return Returns the tags. 369 */ 370 public List<String> getTags() { 371 return tags; 372 } 373 374 /** 375 * print the entry (only for test) 376 * @return the toString implementation of the entry 377 */ 378 @Override 379 public String toString() { 380 StringBuffer buf = new StringBuffer(); 381 buf.append(in1).append(' '); 382 buf.append(in2).append(' '); 383 buf.append(in3).append(' '); 384 for (int i = 0; i < pagenumbers.size(); i++) { 385 buf.append(pagenumbers.get(i)).append(' '); 386 } 387 return buf.toString(); 388 } 389 } 390}