2 * Licensed to the Apache Software Foundation (ASF) under one or more
\r
3 * contributor license agreements. See the NOTICE file distributed with
\r
4 * this work for additional information regarding copyright ownership.
\r
5 * The ASF licenses this file to You under the Apache License, Version 2.0
\r
6 * (the "License"); you may not use this file except in compliance with
\r
7 * the License. You may obtain a copy of the License at
\r
9 * http://www.apache.org/licenses/LICENSE-2.0
\r
11 * Unless required by applicable law or agreed to in writing, software
\r
12 * distributed under the License is distributed on an "AS IS" BASIS,
\r
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
14 * See the License for the specific language governing permissions and
\r
15 * limitations under the License.
\r
17 package org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure;
\r
19 import java.util.Iterator;
\r
20 import java.util.Map;
\r
22 import org.apache.pdfbox.cos.COSArray;
\r
23 import org.apache.pdfbox.cos.COSBase;
\r
24 import org.apache.pdfbox.cos.COSDictionary;
\r
25 import org.apache.pdfbox.cos.COSInteger;
\r
26 import org.apache.pdfbox.cos.COSName;
\r
27 import org.apache.pdfbox.cos.COSObject;
\r
28 import org.apache.pdfbox.pdmodel.PDPage;
\r
29 import org.apache.pdfbox.pdmodel.documentinterchange.markedcontent.PDMarkedContent;
\r
32 * A structure element.
\r
34 * @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>,
\r
35 * <a href="mailto:Johannes%20Koch%20%3Ckoch@apache.org%3E">Johannes Koch</a>
\r
36 * @version $Revision: 1.3 $
\r
38 public class PDStructureElement extends PDStructureNode
\r
40 public static final String TYPE = "StructElem";
\r
44 * Constructor with required values.
\r
46 * @param structureType the structure type
\r
47 * @param parent the parent structure node
\r
49 public PDStructureElement(String structureType, PDStructureNode parent)
\r
52 this.setStructureType(structureType);
\r
53 this.setParent(parent);
\r
57 * Constructor for an existing structure element.
\r
59 * @param dic The existing dictionary.
\r
61 public PDStructureElement( COSDictionary dic )
\r
68 * Returns the structure type (S).
\r
70 * @return the structure type
\r
72 public String getStructureType()
\r
74 return this.getCOSDictionary().getNameAsString(COSName.S);
\r
78 * Sets the structure type (S).
\r
80 * @param structureType the structure type
\r
82 public void setStructureType(String structureType)
\r
84 this.getCOSDictionary().setName(COSName.S, structureType);
\r
88 * Returns the parent in the structure hierarchy (P).
\r
90 * @return the parent in the structure hierarchy
\r
92 public PDStructureNode getParent()
\r
94 COSDictionary p = (COSDictionary) this.getCOSDictionary()
\r
95 .getDictionaryObject(COSName.P);
\r
100 return PDStructureNode.create((COSDictionary) p);
\r
104 * Sets the parent in the structure hierarchy (P).
\r
106 * @param structureNode the parent in the structure hierarchy
\r
108 public void setParent(PDStructureNode structureNode)
\r
110 this.getCOSDictionary().setItem(COSName.P, structureNode);
\r
114 * Returns the element identifier (ID).
\r
116 * @return the element identifier
\r
118 public String getElementIdentifier()
\r
120 return this.getCOSDictionary().getString(COSName.ID);
\r
124 * Sets the element identifier (ID).
\r
126 * @param id the element identifier
\r
128 public void setElementIdentifier(String id)
\r
130 this.getCOSDictionary().setString(COSName.ID, id);
\r
134 * Returns the page on which some or all of the content items designated by
\r
135 * the K entry shall be rendered (Pg).
\r
137 * @return the page on which some or all of the content items designated by
\r
138 * the K entry shall be rendered
\r
140 public PDPage getPage()
\r
142 COSDictionary pageDic = (COSDictionary) this.getCOSDictionary()
\r
143 .getDictionaryObject(COSName.PG);
\r
144 if (pageDic == null)
\r
148 return new PDPage(pageDic);
\r
152 * Sets the page on which some or all of the content items designated by
\r
153 * the K entry shall be rendered (Pg).
\r
154 * @param page the page on which some or all of the content items designated
\r
155 * by the K entry shall be rendered.
\r
157 public void setPage(PDPage page)
\r
159 this.getCOSDictionary().setItem(COSName.PG, page);
\r
163 * Returns the attributes together with their revision numbers (A).
\r
165 * @return the attributes
\r
167 public Revisions<PDAttributeObject> getAttributes()
\r
169 Revisions<PDAttributeObject> attributes =
\r
170 new Revisions<PDAttributeObject>();
\r
171 COSBase a = this.getCOSDictionary().getDictionaryObject(COSName.A);
\r
172 if (a instanceof COSArray)
\r
174 COSArray aa = (COSArray) a;
\r
175 Iterator<COSBase> it = aa.iterator();
\r
176 PDAttributeObject ao = null;
\r
177 while (it.hasNext())
\r
179 COSBase item = it.next();
\r
180 if (item instanceof COSDictionary)
\r
182 ao = PDAttributeObject.create((COSDictionary) item);
\r
183 ao.setStructureElement(this);
\r
184 attributes.addObject(ao, 0);
\r
186 else if (item instanceof COSInteger)
\r
188 attributes.setRevisionNumber(ao,
\r
189 ((COSInteger) item).intValue());
\r
193 if (a instanceof COSDictionary)
\r
195 PDAttributeObject ao = PDAttributeObject.create((COSDictionary) a);
\r
196 ao.setStructureElement(this);
\r
197 attributes.addObject(ao, 0);
\r
203 * Sets the attributes together with their revision numbers (A).
\r
205 * @param attributes the attributes
\r
207 public void setAttributes(Revisions<PDAttributeObject> attributes)
\r
209 COSName key = COSName.A;
\r
210 if ((attributes.size() == 1) && (attributes.getRevisionNumber(0) == 0))
\r
212 PDAttributeObject attributeObject = attributes.getObject(0);
\r
213 attributeObject.setStructureElement(this);
\r
214 this.getCOSDictionary().setItem(key, attributeObject);
\r
217 COSArray array = new COSArray();
\r
218 for (int i = 0; i < attributes.size(); i++)
\r
220 PDAttributeObject attributeObject = attributes.getObject(i);
\r
221 attributeObject.setStructureElement(this);
\r
222 int revisionNumber = attributes.getRevisionNumber(i);
\r
223 if (revisionNumber < 0)
\r
225 // TODO throw Exception because revision number must be > -1?
\r
227 array.add(attributeObject);
\r
228 array.add(COSInteger.get(revisionNumber));
\r
230 this.getCOSDictionary().setItem(key, array);
\r
234 * Adds an attribute object.
\r
236 * @param attributeObject the attribute object
\r
238 public void addAttribute(PDAttributeObject attributeObject)
\r
240 COSName key = COSName.A;
\r
241 attributeObject.setStructureElement(this);
\r
242 COSBase a = this.getCOSDictionary().getDictionaryObject(key);
\r
243 COSArray array = null;
\r
244 if (a instanceof COSArray)
\r
246 array = (COSArray) a;
\r
250 array = new COSArray();
\r
254 array.add(COSInteger.get(0));
\r
257 this.getCOSDictionary().setItem(key, array);
\r
258 array.add(attributeObject);
\r
259 array.add(COSInteger.get(this.getRevisionNumber()));
\r
263 * Removes an attribute object.
\r
265 * @param attributeObject the attribute object
\r
267 public void removeAttribute(PDAttributeObject attributeObject)
\r
269 COSName key = COSName.A;
\r
270 COSBase a = this.getCOSDictionary().getDictionaryObject(key);
\r
271 if (a instanceof COSArray)
\r
273 COSArray array = (COSArray) a;
\r
274 array.remove(attributeObject.getCOSObject());
\r
275 if ((array.size() == 2) && (array.getInt(1) == 0))
\r
277 this.getCOSDictionary().setItem(key, array.getObject(0));
\r
282 COSBase directA = a;
\r
283 if (a instanceof COSObject)
\r
285 directA = ((COSObject) a).getObject();
\r
287 if (attributeObject.getCOSObject().equals(directA))
\r
289 this.getCOSDictionary().setItem(key, null);
\r
292 attributeObject.setStructureElement(null);
\r
296 * Updates the revision number for the given attribute object.
\r
298 * @param attributeObject the attribute object
\r
300 public void attributeChanged(PDAttributeObject attributeObject)
\r
302 COSName key = COSName.A;
\r
303 COSBase a = this.getCOSDictionary().getDictionaryObject(key);
\r
304 if (a instanceof COSArray)
\r
306 COSArray array = (COSArray) a;
\r
307 for (int i = 0; i < array.size(); i++)
\r
309 COSBase entry = array.getObject(i);
\r
310 if (entry.equals(attributeObject.getCOSObject()))
\r
312 COSBase next = array.get(i + 1);
\r
313 if (next instanceof COSInteger)
\r
315 array.set(i + 1, COSInteger.get(this.getRevisionNumber()));
\r
322 COSArray array = new COSArray();
\r
324 array.add(COSInteger.get(this.getRevisionNumber()));
\r
325 this.getCOSDictionary().setItem(key, array);
\r
330 * Returns the class names together with their revision numbers (C).
\r
332 * @return the class names
\r
334 public Revisions<String> getClassNames()
\r
336 COSName key = COSName.C;
\r
337 Revisions<String> classNames = new Revisions<String>();
\r
338 COSBase c = this.getCOSDictionary().getDictionaryObject(key);
\r
339 if (c instanceof COSName)
\r
341 classNames.addObject(((COSName) c).getName(), 0);
\r
343 if (c instanceof COSArray)
\r
345 COSArray array = (COSArray) c;
\r
346 Iterator<COSBase> it = array.iterator();
\r
347 String className = null;
\r
348 while (it.hasNext())
\r
350 COSBase item = it.next();
\r
351 if (item instanceof COSName)
\r
353 className = ((COSName) item).getName();
\r
354 classNames.addObject(className, 0);
\r
356 else if (item instanceof COSInteger)
\r
358 classNames.setRevisionNumber(className,
\r
359 ((COSInteger) item).intValue());
\r
367 * Sets the class names together with their revision numbers (C).
\r
369 * @param classNames the class names
\r
371 public void setClassNames(Revisions<String> classNames)
\r
373 if (classNames == null)
\r
377 COSName key = COSName.C;
\r
378 if ((classNames.size() == 1) && (classNames.getRevisionNumber(0) == 0))
\r
380 String className = classNames.getObject(0);
\r
381 this.getCOSDictionary().setName(key, className);
\r
384 COSArray array = new COSArray();
\r
385 for (int i = 0; i < classNames.size(); i++)
\r
387 String className = classNames.getObject(i);
\r
388 int revisionNumber = classNames.getRevisionNumber(i);
\r
389 if (revisionNumber < 0)
\r
391 // TODO throw Exception because revision number must be > -1?
\r
393 array.add(COSName.getPDFName(className));
\r
394 array.add(COSInteger.get(revisionNumber));
\r
396 this.getCOSDictionary().setItem(key, array);
\r
400 * Adds a class name.
\r
402 * @param className the class name
\r
404 public void addClassName(String className)
\r
406 if (className == null)
\r
410 COSName key = COSName.C;
\r
411 COSBase c = this.getCOSDictionary().getDictionaryObject(key);
\r
412 COSArray array = null;
\r
413 if (c instanceof COSArray)
\r
415 array = (COSArray) c;
\r
419 array = new COSArray();
\r
423 array.add(COSInteger.get(0));
\r
426 this.getCOSDictionary().setItem(key, array);
\r
427 array.add(COSName.getPDFName(className));
\r
428 array.add(COSInteger.get(this.getRevisionNumber()));
\r
432 * Removes a class name.
\r
434 * @param className the class name
\r
436 public void removeClassName(String className)
\r
438 if (className == null)
\r
442 COSName key = COSName.C;
\r
443 COSBase c = this.getCOSDictionary().getDictionaryObject(key);
\r
444 COSName name = COSName.getPDFName(className);
\r
445 if (c instanceof COSArray)
\r
447 COSArray array = (COSArray) c;
\r
448 array.remove(name);
\r
449 if ((array.size() == 2) && (array.getInt(1) == 0))
\r
451 this.getCOSDictionary().setItem(key, array.getObject(0));
\r
456 COSBase directC = c;
\r
457 if (c instanceof COSObject)
\r
459 directC = ((COSObject) c).getObject();
\r
461 if (name.equals(directC))
\r
463 this.getCOSDictionary().setItem(key, null);
\r
469 * Returns the revision number (R).
\r
471 * @return the revision number
\r
473 public int getRevisionNumber()
\r
475 return this.getCOSDictionary().getInt(COSName.R, 0);
\r
479 * Sets the revision number (R).
\r
481 * @param revisionNumber the revision number
\r
483 public void setRevisionNumber(int revisionNumber)
\r
485 if (revisionNumber < 0)
\r
487 // TODO throw Exception because revision number must be > -1?
\r
489 this.getCOSDictionary().setInt(COSName.R, revisionNumber);
\r
493 * Increments th revision number
\r
495 public void incrementRevisionNumber()
\r
497 this.setRevisionNumber(this.getRevisionNumber() + 1);
\r
501 * Returns the title (T).
\r
503 * @return the title
\r
505 public String getTitle()
\r
507 return this.getCOSDictionary().getString(COSName.T);
\r
511 * Sets the title (T).
\r
513 * @param title the title
\r
515 public void setTitle(String title)
\r
517 this.getCOSDictionary().setString(COSName.T, title);
\r
521 * Returns the language (Lang).
\r
523 * @return the language
\r
525 public String getLanguage()
\r
527 return this.getCOSDictionary().getString(COSName.LANG);
\r
531 * Sets the language (Lang).
\r
533 * @param language the language
\r
535 public void setLanguage(String language)
\r
537 this.getCOSDictionary().setString(COSName.LANG, language);
\r
541 * Returns the alternate description (Alt).
\r
543 * @return the alternate description
\r
545 public String getAlternateDescription()
\r
547 return this.getCOSDictionary().getString(COSName.ALT);
\r
551 * Sets the alternate description (Alt).
\r
553 * @param alternateDescription the alternate description
\r
555 public void setAlternateDescription(String alternateDescription)
\r
557 this.getCOSDictionary().setString(COSName.ALT, alternateDescription);
\r
561 * Returns the expanded form (E).
\r
563 * @return the expanded form
\r
565 public String getExpandedForm()
\r
567 return this.getCOSDictionary().getString(COSName.E);
\r
571 * Sets the expanded form (E).
\r
573 * @param expandedForm the expanded form
\r
575 public void setExpandedForm(String expandedForm)
\r
577 this.getCOSDictionary().setString(COSName.E, expandedForm);
\r
581 * Returns the actual text (ActualText).
\r
583 * @return the actual text
\r
585 public String getActualText()
\r
587 return this.getCOSDictionary().getString(COSName.ACTUAL_TEXT);
\r
591 * Sets the actual text (ActualText).
\r
593 * @param actualText the actual text
\r
595 public void setActualText(String actualText)
\r
597 this.getCOSDictionary().setString(COSName.ACTUAL_TEXT, actualText);
\r
601 * Returns the standard structure type, the actual structure type is mapped
\r
602 * to in the role map.
\r
604 * @return the standard structure type
\r
606 public String getStandardStructureType()
\r
608 String type = this.getStructureType();
\r
612 mappedType = this.getRoleMap().get(type);
\r
613 if ((mappedType == null) || type.equals(mappedType))
\r
623 * Appends a marked-content sequence kid.
\r
625 * @param markedContent the marked-content sequence
\r
627 public void appendKid(PDMarkedContent markedContent)
\r
629 if (markedContent == null)
\r
633 this.appendKid(COSInteger.get(markedContent.getMCID()));
\r
637 * Appends a marked-content reference kid.
\r
639 * @param markedContentReference the marked-content reference
\r
641 public void appendKid(PDMarkedContentReference markedContentReference)
\r
643 this.appendObjectableKid(markedContentReference);
\r
647 * Appends an object reference kid.
\r
649 * @param objectReference the object reference
\r
651 public void appendKid(PDObjectReference objectReference)
\r
653 this.appendObjectableKid(objectReference);
\r
657 * Inserts a marked-content identifier kid before a reference kid.
\r
659 * @param markedContentIdentifier the marked-content identifier
\r
660 * @param refKid the reference kid
\r
662 public void insertBefore(COSInteger markedContentIdentifier, Object refKid)
\r
664 this.insertBefore((COSBase) markedContentIdentifier, refKid);
\r
668 * Inserts a marked-content reference kid before a reference kid.
\r
670 * @param markedContentReference the marked-content reference
\r
671 * @param refKid the reference kid
\r
673 public void insertBefore(PDMarkedContentReference markedContentReference,
\r
676 this.insertObjectableBefore(markedContentReference, refKid);
\r
680 * Inserts an object reference kid before a reference kid.
\r
682 * @param objectReference the object reference
\r
683 * @param refKid the reference kid
\r
685 public void insertBefore(PDObjectReference objectReference, Object refKid)
\r
687 this.insertObjectableBefore(objectReference, refKid);
\r
691 * Removes a marked-content identifier kid.
\r
693 * @param markedContentIdentifier the marked-content identifier
\r
695 public void removeKid(COSInteger markedContentIdentifier)
\r
697 this.removeKid((COSBase) markedContentIdentifier);
\r
701 * Removes a marked-content reference kid.
\r
703 * @param markedContentReference the marked-content reference
\r
705 public void removeKid(PDMarkedContentReference markedContentReference)
\r
707 this.removeObjectableKid(markedContentReference);
\r
711 * Removes an object reference kid.
\r
713 * @param objectReference the object reference
\r
715 public void removeKid(PDObjectReference objectReference)
\r
717 this.removeObjectableKid(objectReference);
\r
722 * Returns the structure tree root.
\r
724 * @return the structure tree root
\r
726 private PDStructureTreeRoot getStructureTreeRoot()
\r
728 PDStructureNode parent = this.getParent();
\r
729 while (parent instanceof PDStructureElement)
\r
731 parent = ((PDStructureElement) parent).getParent();
\r
733 if (parent instanceof PDStructureTreeRoot)
\r
735 return (PDStructureTreeRoot) parent;
\r
741 * Returns the role map.
\r
743 * @return the role map
\r
745 private Map<String, String> getRoleMap()
\r
747 PDStructureTreeRoot root = this.getStructureTreeRoot();
\r
750 return root.getRoleMap();
\r