]> _ Git - cubeextranet.git/blob
82f8cc5e50d838cbb35cc895a1c99b5ed6cc31b8
[cubeextranet.git] /
1 /*
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
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17 package org.apache.pdfbox.pdmodel.documentinterchange.logicalstructure;
18
19 import java.util.ArrayList;
20 import java.util.Iterator;
21 import java.util.List;
22
23 import org.apache.pdfbox.cos.COSArray;
24 import org.apache.pdfbox.cos.COSBase;
25 import org.apache.pdfbox.cos.COSDictionary;
26 import org.apache.pdfbox.cos.COSInteger;
27 import org.apache.pdfbox.cos.COSName;
28 import org.apache.pdfbox.cos.COSObject;
29 import org.apache.pdfbox.pdmodel.common.COSArrayList;
30 import org.apache.pdfbox.pdmodel.common.COSObjectable;
31 import org.apache.pdfbox.pdmodel.graphics.xobject.PDXObject;
32 import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotation;
33
34 /**
35  * A node in the structure tree.
36  * 
37  * @author Koch
38  * @version $Revision: $
39  */
40 public abstract class PDStructureNode implements COSObjectable
41 {
42
43     /**
44      * Creates a node in the structure tree. Can be either a structure tree root,
45      *  or a structure element.
46      * 
47      * @param node the node dictionary
48      * @return the structure node
49      */
50     public static PDStructureNode create(COSDictionary node)
51     {
52         String type = node.getNameAsString(COSName.TYPE);
53         if ("StructTreeRoot".equals(type))
54         {
55             return new PDStructureTreeRoot(node);
56         }
57         if ((type == null) || "StructElem".equals(type))
58         {
59             return new PDStructureElement(node);
60         }
61         throw new IllegalArgumentException("Dictionary must not include a Type entry with a value that is neither StructTreeRoot nor StructElem.");
62     }
63
64
65     private COSDictionary dictionary;
66
67     protected COSDictionary getCOSDictionary()
68     {
69         return dictionary;
70     }
71
72     /**
73      * Constructor.
74      *
75      * @param type the type
76      */
77     protected PDStructureNode(String type)
78     {
79         this.dictionary = new COSDictionary();
80         this.dictionary.setName(COSName.TYPE, type);
81     }
82
83     /**
84      * Constructor for an existing structure node.
85      *
86      * @param dictionary The existing dictionary.
87      */
88     protected PDStructureNode(COSDictionary dictionary)
89     {
90         this.dictionary = dictionary;
91     }
92
93     /**
94      * {@inheritDoc}
95      */
96     public COSBase getCOSObject()
97     {
98         return this.dictionary;
99     }
100
101     /**
102      * Returns the type.
103      * 
104      * @return the type
105      */
106     public String getType()
107     {
108         return this.getCOSDictionary().getNameAsString(COSName.TYPE);
109     }
110
111     /**
112      * Returns a list of objects for the kids (K).
113      * 
114      * @return a list of objects for the kids
115      */
116     public List<Object> getKids()
117     {
118         List<Object> kidObjects = new ArrayList<Object>();
119         COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
120         if (k instanceof COSArray)
121         {
122             Iterator<COSBase> kids = ((COSArray) k).iterator();
123             while (kids.hasNext())
124             {
125                 COSBase kid = kids.next();
126                 Object kidObject = this.createObject(kid);
127                 if (kidObject != null)
128                 {
129                     kidObjects.add(kidObject);
130                 }
131             }
132         }
133         else
134         {
135             Object kidObject = this.createObject(k);
136             if (kidObject != null)
137             {
138                 kidObjects.add(kidObject);
139             }
140         }
141         return kidObjects;
142     }
143
144     /**
145      * Sets the kids (K).
146      * 
147      * @param kids the kids
148      */
149     public void setKids(List<Object> kids)
150     {
151         this.getCOSDictionary().setItem(COSName.K,
152             COSArrayList.converterToCOSArray(kids));
153     }
154
155     /**
156      * Appends a structure element kid.
157      * 
158      * @param structureElement the structure element
159      */
160     public void appendKid(PDStructureElement structureElement)
161     {
162         this.appendObjectableKid(structureElement);
163         structureElement.setParent(this);
164     }
165
166     /**
167      * Appends an objectable kid.
168      * 
169      * @param objectable the objectable
170      */
171     protected void appendObjectableKid(COSObjectable objectable)
172     {
173         if (objectable == null)
174         {
175             return;
176         }
177         this.appendKid(objectable.getCOSObject());
178     }
179
180     /**
181      * Appends a COS base kid.
182      * 
183      * @param object the COS base
184      */
185     protected void appendKid(COSBase object)
186     {
187         if (object == null)
188         {
189             return;
190         }
191         COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
192         if (k == null)
193         {
194             // currently no kid: set new kid as kids
195             this.getCOSDictionary().setItem(COSName.K, object);
196         }
197         else if (k instanceof COSArray)
198         {
199             // currently more than one kid: add new kid to existing array
200             COSArray array = (COSArray) k;
201             array.add(object);
202         }
203         else
204         {
205             // currently one kid: put current and new kid into array and set array as kids
206             COSArray array = new COSArray();
207             array.add(k);
208             array.add(object);
209             this.getCOSDictionary().setItem(COSName.K, array);
210         }
211     }
212
213     /**
214      * Inserts a structure element kid before a reference kid.
215      * 
216      * @param newKid the structure element
217      * @param refKid the reference kid
218      */
219     public void insertBefore(PDStructureElement newKid, Object refKid)
220     {
221         this.insertObjectableBefore(newKid, refKid);
222     }
223
224     /**
225      * Inserts an objectable kid before a reference kid.
226      * 
227      * @param newKid the objectable
228      * @param refKid the reference kid
229      */
230     protected void insertObjectableBefore(COSObjectable newKid, Object refKid)
231     {
232         if (newKid == null)
233         {
234             return;
235         }
236         this.insertBefore(newKid.getCOSObject(), refKid);
237     }
238
239     /**
240      * Inserts an COS base kid before a reference kid.
241      * 
242      * @param newKid the COS base
243      * @param refKid the reference kid
244      */
245     protected void insertBefore(COSBase newKid, Object refKid)
246     {
247         if ((newKid == null) || (refKid == null))
248         {
249             return;
250         }
251         COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
252         if (k == null)
253         {
254             return;
255         }
256         COSBase refKidBase = null;
257         if (refKid instanceof COSObjectable)
258         {
259             refKidBase = ((COSObjectable) refKid).getCOSObject();
260         }
261         else if (refKid instanceof COSInteger)
262         {
263             refKidBase = (COSInteger) refKid;
264         }
265         if (k instanceof COSArray)
266         {
267             COSArray array = (COSArray) k;
268             int refIndex = array.indexOfObject(refKidBase);
269             array.add(refIndex, newKid.getCOSObject());
270         }
271         else
272         {
273             boolean onlyKid = k.equals(refKidBase);
274             if (!onlyKid && (k instanceof COSObject))
275             {
276                 COSBase kObj = ((COSObject) k).getObject();
277                 onlyKid = kObj.equals(refKidBase);
278             }
279             if (onlyKid)
280             {
281                 COSArray array = new COSArray();
282                 array.add(newKid);
283                 array.add(refKidBase);
284                 this.getCOSDictionary().setItem(COSName.K, array);
285             }
286         }
287     }
288
289     /**
290      * Removes a structure element kid.
291      * 
292      * @param structureElement the structure element
293      * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
294      */
295     public boolean removeKid(PDStructureElement structureElement)
296     {
297         boolean removed = this.removeObjectableKid(structureElement);
298         if (removed)
299         {
300             structureElement.setParent(null);
301         }
302         return removed;
303     }
304
305     /**
306      * Removes an objectable kid.
307      * 
308      * @param objectable the objectable
309      * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
310      */
311     protected boolean removeObjectableKid(COSObjectable objectable)
312     {
313         if (objectable == null)
314         {
315             return false;
316         }
317         return this.removeKid(objectable.getCOSObject());
318     }
319
320     /**
321      * Removes a COS base kid.
322      * 
323      * @param object the COS base
324      * @return <code>true</code> if the kid was removed, <code>false</code> otherwise
325      */
326     protected boolean removeKid(COSBase object)
327     {
328         if (object == null)
329         {
330             return false;
331         }
332         COSBase k = this.getCOSDictionary().getDictionaryObject(COSName.K);
333         if (k == null)
334         {
335             // no kids: objectable is not a kid
336             return false;
337         }
338         else if (k instanceof COSArray)
339         {
340             // currently more than one kid: remove kid from existing array
341             COSArray array = (COSArray) k;
342             boolean removed = array.removeObject(object);
343             // if now only one kid: set remaining kid as kids
344             if (array.size() == 1)
345             {
346                 this.getCOSDictionary().setItem(COSName.K, array.getObject(0));
347             }
348             return removed;
349         }
350         else
351         {
352             // currently one kid: if current kid equals given object, remove kids entry
353             boolean onlyKid = k.equals(object);
354             if (!onlyKid && (k instanceof COSObject))
355             {
356                 COSBase kObj = ((COSObject) k).getObject();
357                 onlyKid = kObj.equals(object);
358             }
359             if (onlyKid)
360             {
361                 this.getCOSDictionary().setItem(COSName.K, null);
362                 return true;
363             }
364             return false;
365         }
366     }
367
368     /**
369      * Creates an object for a kid of this structure node.
370      * The type of object depends on the type of the kid. It can be
371      * <ul>
372      * <li>a {@link PDStructureElement},</li>
373      * <li>a {@link PDAnnotation},</li>
374      * <li>a {@link PDXObject},</li>
375      * <li>a {@link PDMarkedContentReference}</li>
376      * <li>a {@link Integer}</li>
377      * </ul>
378      * 
379      * @param kid the kid
380      * @return the object
381      */
382     protected Object createObject(COSBase kid)
383     {
384         COSDictionary kidDic = null;
385         if (kid instanceof COSDictionary)
386         {
387             kidDic = (COSDictionary) kid;
388         }
389         else if (kid instanceof COSObject)
390         {
391             COSBase base = ((COSObject) kid).getObject();
392             if (base instanceof COSDictionary)
393             {
394                 kidDic = (COSDictionary) base;
395             }
396         }
397         if (kidDic != null)
398         {
399             String type = kidDic.getNameAsString(COSName.TYPE);
400             if ((type == null) || PDStructureElement.TYPE.equals(type))
401             {
402                 // A structure element dictionary denoting another structure
403                 // element
404                 return new PDStructureElement(kidDic);
405             }
406             else if (PDObjectReference.TYPE.equals(type))
407             {
408                 // An object reference dictionary denoting a PDF object
409                 return new PDObjectReference(kidDic);
410             }
411             else if (PDMarkedContentReference.TYPE.equals(type))
412             {
413                 // A marked-content reference dictionary denoting a
414                 // marked-content sequence
415                 return new PDMarkedContentReference(kidDic);
416             }
417         }
418         else if (kid instanceof COSInteger)
419         {
420             // An integer marked-content identifier denoting a
421             // marked-content sequence
422             COSInteger mcid = (COSInteger) kid;
423             return mcid.intValue();
424         }
425         return null;
426     }
427
428 }