1
2 /* ====================================================================
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================== */
18
19
20
21 package org.apache.poi.hslf.model;
22
23 import java.util.Vector;
24 import java.util.Iterator;
25 import java.awt;
26
27 import org.apache.poi.hslf.record.SlideAtom;
28 import org.apache.poi.hslf.record.TextHeaderAtom;
29 import org.apache.poi.hslf.record.ColorSchemeAtom;
30 import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
31 import org.apache.poi.ddf.EscherDggRecord;
32 import org.apache.poi.ddf.EscherContainerRecord;
33 import org.apache.poi.ddf.EscherDgRecord;
34 import org.apache.poi.ddf.EscherSpRecord;
35
36 /**
37 * This class represents a slide in a PowerPoint Document. It allows
38 * access to the text within, and the layout. For now, it only does
39 * the text side of things though
40 *
41 * @author Nick Burch
42 * @author Yegor Kozlov
43 */
44
45 public class Slide extends Sheet
46 {
47 private int _slideNo;
48 private SlideAtomsSet _atomSet;
49 private TextRun[] _runs;
50 private Notes _notes; // usermodel needs to set this
51
52 /**
53 * Constructs a Slide from the Slide record, and the SlideAtomsSet
54 * containing the text.
55 * Initialises TextRuns, to provide easier access to the text
56 *
57 * @param slide the Slide record we're based on
58 * @param notes the Notes sheet attached to us
59 * @param atomSet the SlideAtomsSet to get the text from
60 */
61 public Slide(org.apache.poi.hslf.record.Slide slide, Notes notes, SlideAtomsSet atomSet, int slideIdentifier, int slideNumber) {
62 super(slide, slideIdentifier);
63
64 _notes = notes;
65 _atomSet = atomSet;
66 _slideNo = slideNumber;
67
68 // Grab the TextRuns from the PPDrawing
69 TextRun[] _otherRuns = findTextRuns(getPPDrawing());
70
71 // For the text coming in from the SlideAtomsSet:
72 // Build up TextRuns from pairs of TextHeaderAtom and
73 // one of TextBytesAtom or TextCharsAtom
74 Vector textRuns = new Vector();
75 if(_atomSet != null) {
76 findTextRuns(_atomSet.getSlideRecords(),textRuns);
77 } else {
78 // No text on the slide, must just be pictures
79 }
80
81 // Build an array, more useful than a vector
82 _runs = new TextRun[textRuns.size()+_otherRuns.length];
83 // Grab text from SlideListWithTexts entries
84 int i=0;
85 for(i=0; i<textRuns.size(); i++) {
86 _runs[i] = (TextRun)textRuns.get(i);
87 _runs[i].setSheet(this);
88 }
89 // Grab text from slide's PPDrawing
90 for(int k=0; k<_otherRuns.length; i++, k++) {
91 _runs[i] = _otherRuns[k];
92 _runs[i].setSheet(this);
93 }
94 }
95
96 /**
97 * Create a new Slide instance
98 * @param sheetNumber The internal number of the sheet, as used by PersistPtrHolder
99 * @param slideNumber The user facing number of the sheet
100 */
101 public Slide(int sheetNumber, int sheetRefId, int slideNumber){
102 super(new org.apache.poi.hslf.record.Slide(), sheetNumber);
103 _slideNo = slideNumber;
104 getSheetContainer().setSheetId(sheetRefId);
105 }
106
107 /**
108 * Sets the Notes that are associated with this. Updates the
109 * references in the records to point to the new ID
110 */
111 public void setNotes(Notes notes) {
112 _notes = notes;
113
114 // Update the Slide Atom's ID of where to point to
115 SlideAtom sa = getSlideRecord().getSlideAtom();
116
117 if(notes == null) {
118 // Set to 0
119 sa.setNotesID(0);
120 } else {
121 // Set to the value from the notes' sheet id
122 sa.setNotesID(notes._getSheetNumber());
123 }
124 }
125
126 /**
127 * Changes the Slide's (external facing) page number.
128 * @see org.apache.poi.hslf.usermodel.SlideShow#reorderSlide(int, int)
129 */
130 public void setSlideNumber(int newSlideNumber) {
131 _slideNo = newSlideNumber;
132 }
133
134 /**
135 * Called by SlideShow ater a new slide is created.
136 * <p>
137 * For Slide we need to do the following:
138 * <li> set id of the drawing group.
139 * <li> set shapeId for the container descriptor and background
140 * </p>
141 */
142 public void onCreate(){
143 //initialize drawing group id
144 EscherDggRecord dgg = getSlideShow().getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
145 EscherContainerRecord dgContainer = (EscherContainerRecord)getSheetContainer().getPPDrawing().getEscherRecords()[0];
146 EscherDgRecord dg = (EscherDgRecord) Shape.getEscherChild(dgContainer, EscherDgRecord.RECORD_ID);
147 int dgId = dgg.getMaxDrawingGroupId() + 1;
148 dg.setOptions((short)(dgId << 4));
149 dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
150 dgg.setMaxDrawingGroupId(dgId);
151
152 for (Iterator it = dgContainer.getChildContainers().iterator(); it.hasNext(); ) {
153 EscherContainerRecord c = (EscherContainerRecord)it.next();
154 EscherSpRecord spr = null;
155 switch(c.getRecordId()){
156 case EscherContainerRecord.SPGR_CONTAINER:
157 EscherContainerRecord dc = (EscherContainerRecord)c.getChildRecords().get(0);
158 spr = dc.getChildById(EscherSpRecord.RECORD_ID);
159 break;
160 case EscherContainerRecord.SP_CONTAINER:
161 spr = c.getChildById(EscherSpRecord.RECORD_ID);
162 break;
163 }
164 if(spr != null) spr.setShapeId(allocateShapeId());
165 }
166
167 //PPT doen't increment the number of saved shapes for group descriptor and background
168 dg.setNumShapes(1);
169 }
170
171 /**
172 * Create a <code>TextBox</code> object that represents the slide's title.
173 *
174 * @return <code>TextBox</code> object that represents the slide's title.
175 */
176 public TextBox addTitle() {
177 Placeholder pl = new Placeholder();
178 pl.setShapeType(ShapeTypes.Rectangle);
179 pl.getTextRun().setRunType(TextHeaderAtom.TITLE_TYPE);
180 pl.setText("Click to edit title");
181 pl.setAnchor(new java.awt.Rectangle(54, 48, 612, 90));
182 addShape(pl);
183 return pl;
184 }
185
186
187 // Complex Accesser methods follow
188
189 /**
190 * Return title of this slide or <code>null</code> if the slide does not have title.
191 * <p>
192 * The title is a run of text of type <code>TextHeaderAtom.CENTER_TITLE_TYPE</code> or
193 * <code>TextHeaderAtom.TITLE_TYPE</code>
194 * </p>
195 *
196 * @see TextHeaderAtom
197 *
198 * @return title of this slide
199 */
200 public String getTitle(){
201 TextRun[] txt = getTextRuns();
202 for (int i = 0; i < txt.length; i++) {
203 int type = txt[i].getRunType();
204 if (type == TextHeaderAtom.CENTER_TITLE_TYPE ||
205 type == TextHeaderAtom.TITLE_TYPE ){
206 String title = txt[i].getText();
207 return title;
208 }
209 }
210 return null;
211 }
212
213 // Simple Accesser methods follow
214
215 /**
216 * Returns an array of all the TextRuns found
217 */
218 public TextRun[] getTextRuns() { return _runs; }
219
220 /**
221 * Returns the (public facing) page number of this slide
222 */
223 public int getSlideNumber() { return _slideNo; }
224
225 /**
226 * Returns the underlying slide record
227 */
228 public org.apache.poi.hslf.record.Slide getSlideRecord() {
229 return (org.apache.poi.hslf.record.Slide)getSheetContainer();
230 }
231
232 /**
233 * Returns the Notes Sheet for this slide, or null if there isn't one
234 */
235 public Notes getNotesSheet() { return _notes; }
236
237 /**
238 * @return set of records inside <code>SlideListWithtext</code> container
239 * which hold text data for this slide (typically for placeholders).
240 */
241 protected SlideAtomsSet getSlideAtomsSet() { return _atomSet; }
242
243 /**
244 * Returns master sheet associated with this slide.
245 * It can be either SlideMaster or TitleMaster objects.
246 *
247 * @return the master sheet associated with this slide.
248 */
249 public MasterSheet getMasterSheet(){
250 SlideMaster[] master = getSlideShow().getSlidesMasters();
251 SlideAtom sa = getSlideRecord().getSlideAtom();
252 int masterId = sa.getMasterID();
253 MasterSheet sheet = null;
254 for (int i = 0; i < master.length; i++) {
255 if (masterId == master[i]._getSheetNumber()) {
256 sheet = master[i];
257 break;
258 }
259 }
260 if (sheet == null){
261 TitleMaster[] titleMaster = getSlideShow().getTitleMasters();
262 if(titleMaster != null) for (int i = 0; i < titleMaster.length; i++) {
263 if (masterId == titleMaster[i]._getSheetNumber()) {
264 sheet = titleMaster[i];
265 break;
266 }
267 }
268 }
269 return sheet;
270 }
271
272 /**
273 * Change Master of this slide.
274 */
275 public void setMasterSheet(MasterSheet master){
276 SlideAtom sa = getSlideRecord().getSlideAtom();
277 int sheetNo = master._getSheetNumber();
278 sa.setMasterID(sheetNo);
279 }
280
281 /**
282 * Sets whether this slide follows master background
283 *
284 * @param flag <code>true</code> if the slide follows master,
285 * <code>false</code> otherwise
286 */
287 public void setFollowMasterBackground(boolean flag){
288 SlideAtom sa = getSlideRecord().getSlideAtom();
289 sa.setFollowMasterBackground(flag);
290 }
291
292 /**
293 * Whether this slide follows master sheet background
294 *
295 * @return <code>true</code> if the slide follows master background,
296 * <code>false</code> otherwise
297 */
298 public boolean getFollowMasterBackground(){
299 SlideAtom sa = getSlideRecord().getSlideAtom();
300 return sa.getFollowMasterBackground();
301 }
302
303 /**
304 * Sets whether this slide draws master sheet objects
305 *
306 * @param flag <code>true</code> if the slide draws master sheet objects,
307 * <code>false</code> otherwise
308 */
309 public void setFollowMasterObjects(boolean flag){
310 SlideAtom sa = getSlideRecord().getSlideAtom();
311 sa.setFollowMasterObjects(flag);
312 }
313
314 /**
315 * Whether this slide follows master color scheme
316 *
317 * @return <code>true</code> if the slide follows master color scheme,
318 * <code>false</code> otherwise
319 */
320 public boolean getFollowMasterScheme(){
321 SlideAtom sa = getSlideRecord().getSlideAtom();
322 return sa.getFollowMasterScheme();
323 }
324
325 /**
326 * Sets whether this slide draws master color scheme
327 *
328 * @param flag <code>true</code> if the slide draws master color scheme,
329 * <code>false</code> otherwise
330 */
331 public void setFollowMasterScheme(boolean flag){
332 SlideAtom sa = getSlideRecord().getSlideAtom();
333 sa.setFollowMasterScheme(flag);
334 }
335
336 /**
337 * Whether this slide draws master sheet objects
338 *
339 * @return <code>true</code> if the slide draws master sheet objects,
340 * <code>false</code> otherwise
341 */
342 public boolean getFollowMasterObjects(){
343 SlideAtom sa = getSlideRecord().getSlideAtom();
344 return sa.getFollowMasterObjects();
345 }
346
347 /**
348 * Background for this slide.
349 */
350 public Background getBackground() {
351 if(getFollowMasterBackground())
352 return getMasterSheet().getBackground();
353 else
354 return super.getBackground();
355 }
356
357 /**
358 * Color scheme for this slide.
359 */
360 public ColorSchemeAtom getColorScheme() {
361 if(getFollowMasterScheme()){
362 return getMasterSheet().getColorScheme();
363 }
364 return super.getColorScheme();
365 }
366
367 public void draw(Graphics2D graphics){
368 MasterSheet master = getMasterSheet();
369 if(getFollowMasterBackground()) master.getBackground().draw(graphics);
370 if(getFollowMasterObjects()){
371 Shape[] sh = master.getShapes();
372 for (int i = 0; i < sh.length; i++) {
373 if(MasterSheet.isPlaceholder(sh[i])) continue;
374
375 sh[i].draw(graphics);
376 }
377 }
378 Shape[] sh = getShapes();
379 for (int i = 0; i < sh.length; i++) {
380 sh[i].draw(graphics);
381 }
382 }
383
384 }