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