1 16 17 package org.apache.cocoon.transformation.pagination; 18 19 import java.util.ArrayList ; 20 import java.util.HashMap ; 21 import java.util.Iterator ; 22 import java.util.Map ; 23 24 import org.apache.cocoon.Modifiable; 25 import org.apache.cocoon.util.ResizableContainer; 26 import org.xml.sax.Attributes ; 27 import org.xml.sax.SAXException ; 28 import org.xml.sax.helpers.DefaultHandler ; 29 30 48 49 99 public class Pagesheet extends DefaultHandler implements Cloneable , Modifiable { 100 101 private int level = 0; 103 private int pg = 0; 104 private long lastModified; 105 private PageRules rules; 106 107 ResizableContainer pageRules; 109 110 Map itemGroupsPerName; 111 Map itemGroupsPerElement; 112 Map itemListsPerName; 113 Map itemListsPerElement; 114 115 private ResizableContainer pages; 117 private Page currentPage = null; 118 private int pageCounter = 1; 119 private int elementCounter = 0; 120 private int descendant = 0; 121 122 private static class Page { 123 public int elementStart; 124 public int elementEnd; 125 public int characters; 126 127 public Page(PageRules rules, int elementStart) { 128 this.elementStart = elementStart; 129 130 if (rules.elementCount>0) { 131 this.elementEnd = this.elementStart+rules.elementCount-1; 132 } else { 133 this.elementEnd = this.elementStart+1; 134 } 135 } 136 137 public boolean validInPage(int elementCounter) { 138 return (this.elementStart<=elementCounter) && 139 (elementCounter<=this.elementEnd); 140 } 141 } 142 143 private static class ItemList extends ArrayList { 144 public ItemList(int capacity) { 145 super(capacity); 146 } 147 148 public void addItem(int page) { 149 this.add(new Integer (page)); 150 } 151 152 public int getPageForItem(int item) { 153 Integer i = (Integer ) this.get(item-1); 154 155 return (i==null) ? 0 : i.intValue(); 156 } 157 158 public boolean valid(int item) { 159 return (item==this.size()); 160 } 161 } 162 163 164 public Pagesheet() { 165 this.pages = new ResizableContainer(2); 166 } 167 168 private Pagesheet(ResizableContainer rules, Map itemGroupsPerName, 169 Map itemGroupsPerElement) { 170 this.pageRules = rules; 171 this.itemGroupsPerName = itemGroupsPerName; 172 this.itemGroupsPerElement = itemGroupsPerElement; 173 174 this.pages = new ResizableContainer(5); 175 176 if ((this.itemGroupsPerName!=null) && 177 (this.itemGroupsPerElement!=null)) { 178 this.itemListsPerName = new HashMap (itemGroupsPerName.size()); 179 this.itemListsPerElement = new HashMap (itemGroupsPerName.size()); 180 181 Iterator iter = itemGroupsPerName.values().iterator(); 182 183 for (; iter.hasNext(); ) { 184 ItemGroup group = (ItemGroup) iter.next(); 185 ItemList list = new ItemList(10); 186 187 this.itemListsPerName.put(group.getName(), list); 188 this.itemListsPerElement.put(group.getElementURI()+ 189 group.getElementName(), list); 190 } 191 } 192 } 193 194 196 public void startPrefixMapping(String prefix, 197 String uri) throws SAXException { 198 if ( !uri.equals(Paginator.PAGINATE_URI)) { 199 throw new SAXException ("The pagesheet's namespace is not supported."); 200 } 201 } 202 203 public void startElement(String uri, String loc, String raw, 204 Attributes a) throws SAXException { 205 level++; 206 switch (level) { 207 case 1 : 208 if (loc.equals("pagesheet")) { 209 return; 211 } 212 break; 213 214 case 2 : 215 if (loc.equals("rules")) { 216 if (this.pageRules == null) { 217 this.pageRules = new ResizableContainer(2); 218 } 219 String key = a.getValue("page"); 220 221 if (key!=null) { 222 try { 223 pg = Integer.parseInt(key); 224 } catch (NumberFormatException e) { 225 throw new SAXException ("Syntax error: the attribute 'rules/@page' must contain a number"); 226 } 227 } else { 228 pg = 0; 229 } 230 rules = new PageRules(); 231 return; 232 } else if (loc.equals("items")) { 233 if (this.itemGroupsPerName==null) { 234 this.itemGroupsPerName = new HashMap (2); 235 } 236 if (this.itemGroupsPerElement==null) { 237 this.itemGroupsPerElement = new HashMap (2); 238 } 239 return; 240 } 241 break; 242 243 case 3 : 244 if (loc.equals("count")) { 245 rules.elementName = a.getValue("name"); 246 rules.elementURI = a.getValue("namespace"); 247 248 if (a.getValue("type").equals("element")) { 249 try { 250 rules.elementCount = Integer.parseInt(a.getValue("num")); 251 } catch (NumberFormatException e) { 252 throw new SAXException ("Syntax error: the attribute 'count/@num' must contain a number"); 253 } 254 } else if (a.getValue("type").equals("chars")) { 255 try { 256 rules.charCount = Integer.parseInt(a.getValue("num")); 257 } catch (NumberFormatException e) { 258 throw new SAXException ("Syntax error: the attribute 'count/@num' must contain a number."); 259 } 260 } else { 261 throw new SAXException ("Syntax error: count type not supported."); 262 } 263 return; 264 } else if (loc.equals("link")) { 265 if (a.getValue("type").equals("unit")) { 266 try { 267 rules.unitLinks = Integer.parseInt(a.getValue("num")); 268 } catch (NumberFormatException e) { 269 throw new SAXException ("Syntax error: the attribute 'link/@num' must contain a number."); 270 } 271 } else if (a.getValue("type").equals("range")) { 272 try { 273 rules.addRangeLink(a.getValue("value")); 274 } catch (NumberFormatException e) { 275 throw new SAXException ("Syntax error: the attribute 'link/@value' must contain a number."); 276 } 277 } else { 278 throw new SAXException ("Syntax error: link type not supported."); 279 } 280 return; 281 } else if (loc.equals("group")) { 282 String name = a.getValue("name"); 283 284 if (name==null) { 285 throw new SAXException ("Syntax error: the attribute 'group/@name' must be present."); 286 } 287 String elementName = a.getValue("element"); 288 289 if (elementName==null) { 290 throw new SAXException ("Syntax error: the attribute 'group/@element' must be present."); 291 } 292 String elementURI = a.getValue("namespace"); 293 ItemGroup group = new ItemGroup(name, elementURI, 294 elementName); 295 296 this.itemGroupsPerName.put(name, group); 297 this.itemGroupsPerElement.put(elementURI+elementName, 298 group); 299 return; 300 } 301 } 302 throw new SAXException ("Syntax error: element "+raw+ 303 " is not recognized or is misplaced."); 304 } 305 306 public void endElement(String uri, String loc, 307 String raw) throws SAXException { 308 level--; 309 if (loc.equals("rules")) { 310 pageRules.set(pg, rules); 311 } 312 } 313 314 public void endDocument() throws SAXException { 315 if (pageRules.size() == 0) { 316 throw new SAXException ("Pagesheet must contain at least a set of pagination rules."); 317 } 318 if (pageRules.get(0) == null) { 319 throw new SAXException ("Pagesheet must contain the global pagination rules."); 320 } 321 } 322 323 325 public void processStartElement(String uri, String name) { 326 PageRules rules = getPageRules(pageCounter); 327 328 if (rules.match(name, uri)) { 329 elementCounter++; 330 descendant++; 331 332 if (currentPage==null) { 333 currentPage = new Page(rules, 1); 334 } 335 336 if (elementCounter>currentPage.elementEnd) { 337 340 pageCounter++; 341 currentPage = new Page(rules, currentPage.elementEnd+1); 342 } 343 344 pages.set(pageCounter, currentPage); 345 } 346 347 if (itemGroupsPerElement!=null) { 348 String qname = uri+name; 349 ItemGroup group = (ItemGroup) this.itemGroupsPerElement.get(qname); 350 351 if ((group!=null) && (group.match(uri))) { 352 ItemList list = (ItemList) this.itemListsPerElement.get(qname); 353 354 if (list!=null) { 355 list.addItem(pageCounter); 356 } 357 } 358 } 359 } 360 361 public void processEndElement(String uri, String name) { 362 PageRules rules = getPageRules(pageCounter); 363 364 if (rules.match(name, uri)) { 365 descendant--; 366 367 if ((rules.charCount>0) && 368 (currentPage.characters>rules.charCount)) { 369 currentPage.elementEnd = elementCounter; 372 } else if (rules.elementCount==0) { 373 currentPage.elementEnd++; 375 } 376 } 377 } 378 379 public void processCharacters(char[] ch, int index, int len) { 380 if (descendant>0) { 381 currentPage.characters += len; 384 } 385 } 386 387 389 public boolean isInPage(int page, int item, String itemGroup) { 390 return ((descendant==0) || valid(page, item, itemGroup)); 391 } 392 393 public int getTotalPages() { 394 return pageCounter; 395 } 396 397 public int getTotalItems(String itemGroup) { 398 if (this.itemListsPerName==null) { 399 return 0; 400 } 401 ItemList list = (ItemList) this.itemListsPerName.get(itemGroup); 402 403 return (list==null) ? 0 : list.size(); 404 } 405 406 public int getPageForItem(int item, String itemGroup) { 407 if (this.itemListsPerName==null) { 408 return 0; 409 } 410 ItemList list = (ItemList) this.itemListsPerName.get(itemGroup); 411 412 return (list==null) ? 0 : list.getPageForItem(item); 413 } 414 415 public int itemCount(String elementURI, String elementName) { 416 if (this.itemListsPerElement==null) { 417 return 0; 418 } 419 ItemList list = (ItemList) this.itemListsPerElement.get(elementURI+ 420 elementName); 421 422 return (list==null) ? 0 : list.size(); 423 } 424 425 public String getItemGroupName(String elementURI, String elementName) { 426 if (this.itemListsPerElement==null) { 427 return null; 428 } 429 return ((ItemGroup) this.itemGroupsPerElement.get(elementURI+ 430 elementName)).getName(); 431 } 432 433 435 private boolean valid(int page, int item, String itemGroup) { 436 if (item==0) { 437 Page p = (Page) pages.get(page); 438 439 return (p!=null) && (p.validInPage(elementCounter)); 440 } else { 441 if (this.itemListsPerElement==null) { 442 return false; 443 } 444 ItemList list = (ItemList) this.itemListsPerName.get(itemGroup); 445 446 return (list!=null) && (list.valid(item)); 447 } 448 } 449 450 public PageRules getPageRules(int page) { 451 PageRules p = (PageRules) pageRules.get(page); 452 453 return (p!=null) ? p : (PageRules) pageRules.get(0); 454 } 455 456 public void setLastModified(long lastModified) { 457 this.lastModified = lastModified; 458 } 459 460 public boolean modifiedSince(long date) { 461 return (this.lastModified == 0 || date!=this.lastModified); 462 } 463 464 public Object clone() { 465 return new Pagesheet(pageRules, itemGroupsPerName, 466 itemGroupsPerElement); 467 } 468 } 469 | Popular Tags |