001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hslf.model;
019:
020: import org.apache.poi.ddf.EscherContainerRecord;
021: import org.apache.poi.ddf.EscherDgRecord;
022: import org.apache.poi.ddf.EscherRecord;
023: import org.apache.poi.ddf.EscherSpRecord;
024: import org.apache.poi.hslf.record.*;
025: import org.apache.poi.hslf.usermodel.SlideShow;
026:
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.List;
030: import java.util.Vector;
031:
032: /**
033: * This class defines the common format of "Sheets" in a powerpoint
034: * document. Such sheets could be Slides, Notes, Master etc
035: *
036: * @author Nick Burch
037: * @author Yegor Kozlov
038: */
039:
040: public abstract class Sheet {
041: /**
042: * The <code>SlideShow</code> we belong to
043: */
044: private SlideShow _slideShow;
045:
046: /**
047: * Sheet background
048: */
049: private Background _background;
050:
051: /**
052: * Record container that holds sheet data.
053: * For slides it is org.apache.poi.hslf.record.Slide,
054: * for notes it is org.apache.poi.hslf.record.Notes,
055: * for slide masters it is org.apache.poi.hslf.record.SlideMaster, etc.
056: */
057: private SheetContainer _container;
058:
059: private int _sheetNo;
060:
061: public Sheet(SheetContainer container, int sheetNo) {
062: _container = container;
063: _sheetNo = sheetNo;
064: }
065:
066: /**
067: * Returns an array of all the TextRuns in the sheet.
068: */
069: public abstract TextRun[] getTextRuns();
070:
071: /**
072: * Returns the (internal, RefID based) sheet number, as used
073: * to in PersistPtr stuff.
074: */
075: public int _getSheetRefId() {
076: return _container.getSheetId();
077: }
078:
079: /**
080: * Returns the (internal, SlideIdentifier based) sheet number, as used
081: * to reference this sheet from other records.
082: */
083: public int _getSheetNumber() {
084: return _sheetNo;
085: }
086:
087: /**
088: * Fetch the PPDrawing from the underlying record
089: */
090: protected PPDrawing getPPDrawing() {
091: return _container.getPPDrawing();
092: }
093:
094: /**
095: * Fetch the SlideShow we're attached to
096: */
097: public SlideShow getSlideShow() {
098: return _slideShow;
099: }
100:
101: /**
102: * Return record container for this sheet
103: */
104: public SheetContainer getSheetContainer() {
105: return _container;
106: }
107:
108: /**
109: * Set the SlideShow we're attached to.
110: * Also passes it on to our child RichTextRuns
111: */
112: public void setSlideShow(SlideShow ss) {
113: _slideShow = ss;
114: TextRun[] trs = getTextRuns();
115: if (trs != null) {
116: for (int i = 0; i < trs.length; i++) {
117: trs[i].supplySlideShow(_slideShow);
118: }
119: }
120: }
121:
122: /**
123: * For a given PPDrawing, grab all the TextRuns
124: */
125: public static TextRun[] findTextRuns(PPDrawing ppdrawing) {
126: Vector runsV = new Vector();
127: EscherTextboxWrapper[] wrappers = ppdrawing
128: .getTextboxWrappers();
129: for (int i = 0; i < wrappers.length; i++) {
130: int s1 = runsV.size();
131: findTextRuns(wrappers[i].getChildRecords(), runsV);
132: int s2 = runsV.size();
133: if (s2 != s1) {
134: TextRun t = (TextRun) runsV.get(runsV.size() - 1);
135: t.setShapeId(wrappers[i].getShapeId());
136: }
137: }
138: TextRun[] runs = new TextRun[runsV.size()];
139: for (int i = 0; i < runs.length; i++) {
140: runs[i] = (TextRun) runsV.get(i);
141: }
142: return runs;
143: }
144:
145: /**
146: * Scans through the supplied record array, looking for
147: * a TextHeaderAtom followed by one of a TextBytesAtom or
148: * a TextCharsAtom. Builds up TextRuns from these
149: *
150: * @param records the records to build from
151: * @param found vector to add any found to
152: */
153: protected static void findTextRuns(Record[] records, Vector found) {
154: // Look for a TextHeaderAtom
155: for (int i = 0, slwtIndex = 0; i < (records.length - 1); i++) {
156: if (records[i] instanceof TextHeaderAtom) {
157: TextRun trun = null;
158: TextHeaderAtom tha = (TextHeaderAtom) records[i];
159: StyleTextPropAtom stpa = null;
160:
161: // Look for a subsequent StyleTextPropAtom
162: if (i < (records.length - 2)) {
163: if (records[i + 2] instanceof StyleTextPropAtom) {
164: stpa = (StyleTextPropAtom) records[i + 2];
165: }
166: }
167:
168: // See what follows the TextHeaderAtom
169: if (records[i + 1] instanceof TextCharsAtom) {
170: TextCharsAtom tca = (TextCharsAtom) records[i + 1];
171: trun = new TextRun(tha, tca, stpa);
172: } else if (records[i + 1] instanceof TextBytesAtom) {
173: TextBytesAtom tba = (TextBytesAtom) records[i + 1];
174: trun = new TextRun(tha, tba, stpa);
175: } else if (records[i + 1].getRecordType() == 4001l) {
176: // StyleTextPropAtom - Safe to ignore
177: } else if (records[i + 1].getRecordType() == 4010l) {
178: // TextSpecInfoAtom - Safe to ignore
179: } else {
180: System.err
181: .println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by "
182: + records[i + 1].getRecordType());
183: }
184:
185: if (trun != null) {
186: ArrayList lst = new ArrayList();
187: for (int j = i; j < records.length; j++) {
188: if (j > i
189: && records[j] instanceof TextHeaderAtom)
190: break;
191: lst.add(records[j]);
192: }
193: Record[] recs = new Record[lst.size()];
194: lst.toArray(recs);
195: trun._records = recs;
196: trun.setIndex(slwtIndex);
197:
198: found.add(trun);
199: i++;
200: } else {
201: // Not a valid one, so skip on to next and look again
202: }
203: slwtIndex++;
204: }
205: }
206: }
207:
208: /**
209: * Returns all shapes contained in this Sheet
210: *
211: * @return all shapes contained in this Sheet (Slide or Notes)
212: */
213: public Shape[] getShapes() {
214: PPDrawing ppdrawing = getPPDrawing();
215:
216: EscherContainerRecord dg = (EscherContainerRecord) ppdrawing
217: .getEscherRecords()[0];
218: EscherContainerRecord spgr = null;
219: List ch = dg.getChildRecords();
220:
221: for (Iterator it = ch.iterator(); it.hasNext();) {
222: EscherRecord rec = (EscherRecord) it.next();
223: if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
224: spgr = (EscherContainerRecord) rec;
225: break;
226: }
227: }
228: ch = spgr.getChildRecords();
229:
230: ArrayList shapes = new ArrayList();
231: for (int i = 1; i < ch.size(); i++) {
232: EscherContainerRecord sp = (EscherContainerRecord) ch
233: .get(i);
234: Shape sh = ShapeFactory.createShape(sp, null);
235: sh.setSheet(this );
236: shapes.add(sh);
237: }
238:
239: return (Shape[]) shapes.toArray(new Shape[shapes.size()]);
240: }
241:
242: /**
243: * Add a new Shape to this Slide
244: *
245: * @param shape - the Shape to add
246: */
247: public void addShape(Shape shape) {
248: PPDrawing ppdrawing = getPPDrawing();
249:
250: EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing
251: .getEscherRecords()[0];
252: EscherContainerRecord spgr = (EscherContainerRecord) Shape
253: .getEscherChild(dgContainer,
254: EscherContainerRecord.SPGR_CONTAINER);
255: spgr.addChildRecord(shape.getSpContainer());
256:
257: EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(
258: dgContainer, EscherDgRecord.RECORD_ID);
259: dg.setNumShapes(dg.getNumShapes() + 1);
260:
261: int shapeId = dg.getLastMSOSPID() + 1;
262: dg.setLastMSOSPID(shapeId);
263:
264: EscherSpRecord sp = shape.getSpContainer().getChildById(
265: EscherSpRecord.RECORD_ID);
266: if (sp != null)
267: sp.setShapeId(shapeId);
268: shape.setSheet(this );
269: shape.afterInsert(this );
270:
271: // If it's a TextBox, we need to tell the PPDrawing, as it has to
272: // track TextboxWrappers specially
273: if (shape instanceof TextBox) {
274: TextBox tbox = (TextBox) shape;
275: ppdrawing.addTextboxWrapper(tbox._txtbox);
276: }
277: }
278:
279: /**
280: * Return the master sheet .
281: */
282: public abstract MasterSheet getMasterSheet();
283:
284: /**
285: * Color scheme for this sheet.
286: */
287: public ColorSchemeAtom getColorScheme() {
288: return _container.getColorScheme();
289: }
290:
291: /**
292: * Returns the background shape for this sheet.
293: *
294: * @return the background shape for this sheet.
295: */
296: public Background getBackground() {
297: if (_background == null) {
298: PPDrawing ppdrawing = getPPDrawing();
299:
300: EscherContainerRecord dg = (EscherContainerRecord) ppdrawing
301: .getEscherRecords()[0];
302: EscherContainerRecord spContainer = null;
303: List ch = dg.getChildRecords();
304:
305: for (Iterator it = ch.iterator(); it.hasNext();) {
306: EscherRecord rec = (EscherRecord) it.next();
307: if (rec.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
308: spContainer = (EscherContainerRecord) rec;
309: break;
310: }
311: }
312: _background = new Background(spContainer, null);
313: _background.setSheet(this);
314: }
315: return _background;
316: }
317:
318: }
|