2005-05-28 01:36:00 -04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2006-12-22 14:18:16 -05:00
Licensed to the Apache Software Foundation ( ASF ) under one or more
contributor license agreements . See the NOTICE file distributed with
this work for additional information regarding copyright ownership .
The ASF licenses this file to You under the Apache License , Version 2 . 0
( the " License " ) ; you may not use this file except in compliance with
the License . You may obtain a copy of the License at
2005-05-28 01:36:00 -04:00
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an " AS IS " BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = * /
package org.apache.poi.hslf.usermodel ;
import java.util.* ;
2006-03-19 10:59:23 -05:00
import java.awt.Dimension ;
2005-05-28 01:36:00 -04:00
import java.io.* ;
2006-03-26 11:20:08 -05:00
import org.apache.poi.ddf.EscherBSERecord ;
import org.apache.poi.ddf.EscherContainerRecord ;
import org.apache.poi.ddf.EscherOptRecord ;
import org.apache.poi.ddf.EscherRecord ;
2005-05-28 01:36:00 -04:00
import org.apache.poi.hslf.* ;
import org.apache.poi.hslf.model.* ;
2006-03-19 10:59:23 -05:00
import org.apache.poi.hslf.record.Document ;
import org.apache.poi.hslf.record.DocumentAtom ;
2005-09-17 12:44:00 -04:00
import org.apache.poi.hslf.record.FontCollection ;
2005-11-07 17:24:15 -05:00
import org.apache.poi.hslf.record.ParentAwareRecord ;
2006-03-26 14:07:52 -05:00
import org.apache.poi.hslf.record.PositionDependentRecordContainer ;
2005-05-28 01:36:00 -04:00
import org.apache.poi.hslf.record.Record ;
2005-11-07 17:24:15 -05:00
import org.apache.poi.hslf.record.RecordContainer ;
2005-09-17 12:44:00 -04:00
import org.apache.poi.hslf.record.RecordTypes ;
2005-05-28 01:36:00 -04:00
import org.apache.poi.hslf.record.SlideAtom ;
import org.apache.poi.hslf.record.SlideListWithText ;
2006-03-19 12:53:49 -05:00
import org.apache.poi.hslf.record.SlidePersistAtom ;
import org.apache.poi.hslf.record.UserEditAtom ;
2005-05-28 01:36:00 -04:00
import org.apache.poi.hslf.record.SlideListWithText.* ;
2005-06-26 14:09:15 -04:00
import org.apache.poi.hslf.record.PersistPtrHolder ;
import org.apache.poi.hslf.record.PositionDependentRecord ;
2006-01-03 06:54:38 -05:00
import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException ;
2006-07-02 12:02:20 -04:00
import org.apache.poi.util.ArrayUtil ;
2006-11-28 10:54:39 -05:00
import org.apache.poi.util.POILogFactory ;
import org.apache.poi.util.POILogger ;
2005-05-28 01:36:00 -04:00
/ * *
* This class is a friendly wrapper on top of the more scary HSLFSlideShow .
*
* TODO :
* - figure out how to match notes to their correct sheet
* ( will involve understanding DocSlideList and DocNotesList )
* - handle Slide creation cleaner
*
* @author Nick Burch
2006-03-26 11:20:08 -05:00
* @author Yegor kozlov
2005-05-28 01:36:00 -04:00
* /
public class SlideShow
{
// What we're based on
private HSLFSlideShow _hslfSlideShow ;
// Low level contents, as taken from HSLFSlideShow
private Record [ ] _records ;
2005-06-26 14:09:15 -04:00
// Pointers to the most recent versions of the core records
// (Document, Notes, Slide etc)
private Record [ ] _mostRecentCoreRecords ;
2006-03-27 16:35:37 -05:00
// Lookup between the PersitPtr "sheet" IDs, and the position
// in the mostRecentCoreRecords array
private Hashtable _sheetIdToCoreRecordsLookup ;
// Used when adding new core records
private int _highestSheetId ;
2006-03-18 13:56:26 -05:00
// Records that are interesting
2006-03-19 10:59:23 -05:00
private Document _documentRecord ;
2005-06-26 14:09:15 -04:00
2005-05-28 01:36:00 -04:00
// Friendly objects for people to deal with
2006-10-17 14:01:19 -04:00
private SlideMaster [ ] _masters ;
2005-05-28 01:36:00 -04:00
private Slide [ ] _slides ;
private Notes [ ] _notes ;
2005-09-17 12:44:00 -04:00
private FontCollection _fonts ;
2005-05-28 01:36:00 -04:00
2006-11-28 10:54:39 -05:00
// For logging
private POILogger logger = POILogFactory . getLogger ( this . getClass ( ) ) ;
2006-03-26 11:20:08 -05:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Setup Code
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* /
2005-05-28 01:36:00 -04:00
/ * *
* Constructs a Powerpoint document from the underlying
* HSLFSlideShow object . Finds the model stuff from this
*
* @param hslfSlideShow the HSLFSlideShow to base on
* /
public SlideShow ( HSLFSlideShow hslfSlideShow ) throws IOException
{
// Get useful things from our base slideshow
_hslfSlideShow = hslfSlideShow ;
_records = _hslfSlideShow . getRecords ( ) ;
2005-11-07 17:24:15 -05:00
// Handle Parent-aware Reocrds
for ( int i = 0 ; i < _records . length ; i + + ) {
handleParentAwareRecords ( _records [ i ] ) ;
}
2005-05-28 01:36:00 -04:00
2005-06-26 14:09:15 -04:00
// Find the versions of the core records we'll want to use
findMostRecentCoreRecords ( ) ;
2006-03-18 13:56:26 -05:00
2005-06-26 14:09:15 -04:00
// Build up the model level Slides and Notes
buildSlidesAndNotes ( ) ;
}
2005-11-07 17:24:15 -05:00
2006-03-26 11:20:08 -05:00
/ * *
* Constructs a new , empty , Powerpoint document .
* /
public SlideShow ( ) throws IOException {
this ( new HSLFSlideShow ( ) ) ;
}
2005-11-07 17:24:15 -05:00
/ * *
* Find the records that are parent - aware , and tell them
* who their parent is
* /
private void handleParentAwareRecords ( Record baseRecord ) {
// Only need to do something if this is a container record
if ( baseRecord instanceof RecordContainer ) {
RecordContainer br = ( RecordContainer ) baseRecord ;
Record [ ] childRecords = br . getChildRecords ( ) ;
// Loop over child records, looking for interesting ones
for ( int i = 0 ; i < childRecords . length ; i + + ) {
Record record = childRecords [ i ] ;
// Tell parent aware records of their parent
if ( record instanceof ParentAwareRecord ) {
( ( ParentAwareRecord ) record ) . setParentRecord ( br ) ;
}
// Walk on down for the case of container records
if ( record instanceof RecordContainer ) {
handleParentAwareRecords ( record ) ;
}
}
}
}
2005-06-26 14:09:15 -04:00
2005-06-26 15:05:07 -04:00
2005-06-26 14:09:15 -04:00
/ * *
* Use the PersistPtrHolder entries to figure out what is
* the " most recent " version of all the core records
* ( Document , Notes , Slide etc ) , and save a record of them .
* Do this by walking from the oldest PersistPtr to the newest ,
* overwriting any references found along the way with newer ones
* /
private void findMostRecentCoreRecords ( ) {
// To start with, find the most recent in the byte offset domain
Hashtable mostRecentByBytes = new Hashtable ( ) ;
for ( int i = 0 ; i < _records . length ; i + + ) {
if ( _records [ i ] instanceof PersistPtrHolder ) {
PersistPtrHolder pph = ( PersistPtrHolder ) _records [ i ] ;
// If we've already seen any of the "slide" IDs for this
// PersistPtr, remove their old positions
int [ ] ids = pph . getKnownSlideIDs ( ) ;
for ( int j = 0 ; j < ids . length ; j + + ) {
Integer id = new Integer ( ids [ j ] ) ;
if ( mostRecentByBytes . containsKey ( id ) ) {
mostRecentByBytes . remove ( id ) ;
}
}
// Now, update the byte level locations with their latest values
Hashtable thisSetOfLocations = pph . getSlideLocationsLookup ( ) ;
for ( int j = 0 ; j < ids . length ; j + + ) {
Integer id = new Integer ( ids [ j ] ) ;
mostRecentByBytes . put ( id , thisSetOfLocations . get ( id ) ) ;
}
}
}
2005-05-28 01:36:00 -04:00
2005-06-26 14:09:15 -04:00
// We now know how many unique special records we have, so init
// the array
_mostRecentCoreRecords = new Record [ mostRecentByBytes . size ( ) ] ;
2006-03-27 16:35:37 -05:00
// We'll also want to be able to turn the slide IDs into a position
// in this array
_sheetIdToCoreRecordsLookup = new Hashtable ( ) ;
2005-06-26 14:09:15 -04:00
int [ ] allIDs = new int [ _mostRecentCoreRecords . length ] ;
Enumeration ids = mostRecentByBytes . keys ( ) ;
for ( int i = 0 ; i < allIDs . length ; i + + ) {
Integer id = ( Integer ) ids . nextElement ( ) ;
allIDs [ i ] = id . intValue ( ) ;
}
Arrays . sort ( allIDs ) ;
for ( int i = 0 ; i < allIDs . length ; i + + ) {
2006-03-27 16:35:37 -05:00
_sheetIdToCoreRecordsLookup . put ( new Integer ( allIDs [ i ] ) , new Integer ( i ) ) ;
2005-06-26 14:09:15 -04:00
}
2006-03-27 16:35:37 -05:00
// Capture the ID of the highest sheet
_highestSheetId = allIDs [ ( allIDs . length - 1 ) ] ;
2005-06-26 14:09:15 -04:00
// Now convert the byte offsets back into record offsets
for ( int i = 0 ; i < _records . length ; i + + ) {
if ( _records [ i ] instanceof PositionDependentRecord ) {
PositionDependentRecord pdr = ( PositionDependentRecord ) _records [ i ] ;
Integer recordAt = new Integer ( pdr . getLastOnDiskOffset ( ) ) ;
// Is it one we care about?
for ( int j = 0 ; j < allIDs . length ; j + + ) {
Integer thisID = new Integer ( allIDs [ j ] ) ;
Integer thatRecordAt = ( Integer ) mostRecentByBytes . get ( thisID ) ;
if ( thatRecordAt . equals ( recordAt ) ) {
// Bingo. Now, where do we store it?
Integer storeAtI =
2006-03-27 16:35:37 -05:00
( Integer ) _sheetIdToCoreRecordsLookup . get ( thisID ) ;
2005-06-26 14:09:15 -04:00
int storeAt = storeAtI . intValue ( ) ;
2006-03-26 14:07:52 -05:00
// Tell it its Sheet ID, if it cares
if ( pdr instanceof PositionDependentRecordContainer ) {
PositionDependentRecordContainer pdrc =
( PositionDependentRecordContainer ) _records [ i ] ;
pdrc . setSheetId ( thisID . intValue ( ) ) ;
}
2005-06-26 14:09:15 -04:00
// Finally, save the record
_mostRecentCoreRecords [ storeAt ] = _records [ i ] ;
}
}
}
}
2006-03-18 13:56:26 -05:00
// Now look for the interesting records in there
for ( int i = 0 ; i < _mostRecentCoreRecords . length ; i + + ) {
2006-03-27 16:35:37 -05:00
// Check there really is a record at this number
if ( _mostRecentCoreRecords [ i ] ! = null ) {
// Find the Document, and interesting things in it
if ( _mostRecentCoreRecords [ i ] . getRecordType ( ) = = RecordTypes . Document . typeID ) {
_documentRecord = ( Document ) _mostRecentCoreRecords [ i ] ;
_fonts = _documentRecord . getEnvironment ( ) . getFontCollection ( ) ;
}
} else {
2006-07-02 12:02:20 -04:00
// No record at this number
// Odd, but not normally a problem
2006-03-18 13:56:26 -05:00
}
}
2005-06-26 14:09:15 -04:00
}
2006-06-27 14:15:32 -04:00
/ * *
* For a given SlideAtomsSet , return the core record , based on the refID from the
* SlidePersistAtom
* /
private Record getCoreRecordForSAS ( SlideAtomsSet sas ) {
SlidePersistAtom spa = sas . getSlidePersistAtom ( ) ;
int refID = spa . getRefID ( ) ;
return getCoreRecordForRefID ( refID ) ;
}
/ * *
* For a given refID ( the internal , 0 based numbering scheme ) , return the
* core record
* @param refID the refID
* /
private Record getCoreRecordForRefID ( int refID ) {
Integer coreRecordId = ( Integer )
_sheetIdToCoreRecordsLookup . get ( new Integer ( refID ) ) ;
Record r = _mostRecentCoreRecords [ coreRecordId . intValue ( ) ] ;
return r ;
}
2005-06-26 14:09:15 -04:00
/ * *
* Build up model level Slide and Notes objects , from the underlying
* records .
* /
private void buildSlidesAndNotes ( ) {
2006-03-18 13:56:26 -05:00
// Ensure we really found a Document record earlier
2005-11-24 05:46:45 -05:00
// If we didn't, then the file is probably corrupt
2006-03-18 13:56:26 -05:00
if ( _documentRecord = = null ) {
2006-01-03 06:54:38 -05:00
throw new CorruptPowerPointFileException ( " The PowerPoint file didn't contain a Document Record in its PersistPtr blocks. It is probably corrupt. " ) ;
2005-11-24 05:46:45 -05:00
}
2005-05-28 01:36:00 -04:00
2006-03-19 11:09:51 -05:00
// Fetch the SlideListWithTexts in the most up-to-date Document Record
2005-05-28 01:36:00 -04:00
//
2006-06-27 14:15:32 -04:00
// As far as we understand it:
// * The first SlideListWithText will contain a SlideAtomsSet
// for each of the master slides
// * The second SlideListWithText will contain a SlideAtomsSet
// for each of the slides, in their current order
// These SlideAtomsSets will normally contain text
// * The third SlideListWithText (if present), will contain a
// SlideAtomsSet for each Notes
// These SlideAtomsSets will not normally contain text
2005-06-26 15:05:07 -04:00
//
2006-06-27 14:15:32 -04:00
// Having indentified the masters, slides and notes + their orders,
// we have to go and find their matching records
// We always use the latest versions of these records, and use the
// SlideAtom/NotesAtom to match them with the StyleAtomSet
SlideListWithText masterSLWT = _documentRecord . getMasterSlideListWithText ( ) ;
SlideListWithText slidesSLWT = _documentRecord . getSlideSlideListWithText ( ) ;
SlideListWithText notesSLWT = _documentRecord . getNotesSlideListWithText ( ) ;
2007-01-09 13:51:29 -05:00
2006-12-14 06:50:54 -05:00
// Find master slides
2007-01-09 13:51:29 -05:00
// These can be MainMaster records, but oddly they can also be
// Slides or Notes, and possibly even other odd stuff....
// About the only thing you can say is that the master details are in
// the first SLWT.
2006-10-17 14:01:19 -04:00
SlideAtomsSet [ ] masterSets = new SlideAtomsSet [ 0 ] ;
2007-01-09 13:51:29 -05:00
org . apache . poi . hslf . record . MainMaster [ ] mainMasterRecords = null ;
2006-10-17 14:01:19 -04:00
if ( masterSLWT ! = null ) {
masterSets = masterSLWT . getSlideAtomsSets ( ) ;
2006-12-14 06:50:54 -05:00
2007-01-09 13:51:29 -05:00
// For now, we only care about the records which are MainMasters
// (In future, we might want to know about the other too)
ArrayList mmr = new ArrayList ( ) ;
2006-12-14 06:50:54 -05:00
for ( int i = 0 ; i < masterSets . length ; i + + ) {
Record r = getCoreRecordForSAS ( masterSets [ i ] ) ;
if ( r instanceof org . apache . poi . hslf . record . Slide ) {
2007-01-09 13:51:29 -05:00
// Slide master, skip
2006-12-14 06:50:54 -05:00
} else if ( r instanceof org . apache . poi . hslf . record . MainMaster ) {
2007-01-09 13:51:29 -05:00
mmr . add ( r ) ;
2006-12-14 06:50:54 -05:00
}
}
2007-01-09 13:51:29 -05:00
mainMasterRecords = new org . apache . poi . hslf . record . MainMaster [ mmr . size ( ) ] ;
mmr . toArray ( mainMasterRecords ) ;
2006-10-17 14:01:19 -04:00
}
2006-12-14 06:50:54 -05:00
// Having sorted out the masters, that leaves the notes and slides
2006-06-27 14:15:32 -04:00
// Start by finding the notes records to go with the entries in
// notesSLWT
org . apache . poi . hslf . record . Notes [ ] notesRecords ;
SlideAtomsSet [ ] notesSets = new SlideAtomsSet [ 0 ] ;
Hashtable slideIdToNotes = new Hashtable ( ) ;
if ( notesSLWT = = null ) {
// None
notesRecords = new org . apache . poi . hslf . record . Notes [ 0 ] ;
} else {
// Match up the records and the SlideAtomSets
notesSets = notesSLWT . getSlideAtomsSets ( ) ;
notesRecords = new org . apache . poi . hslf . record . Notes [ notesSets . length ] ;
for ( int i = 0 ; i < notesSets . length ; i + + ) {
// Get the right core record
Record r = getCoreRecordForSAS ( notesSets [ i ] ) ;
2006-03-27 16:35:37 -05:00
2006-06-27 14:15:32 -04:00
// Ensure it really is a notes record
if ( r instanceof org . apache . poi . hslf . record . Notes ) {
notesRecords [ i ] = ( org . apache . poi . hslf . record . Notes ) r ;
2005-06-26 15:05:07 -04:00
} else {
2006-11-28 10:54:39 -05:00
logger . log ( POILogger . ERROR , " A Notes SlideAtomSet at " + i + " said its record was at refID " + notesSets [ i ] . getSlidePersistAtom ( ) . getRefID ( ) + " , but that was actually a " + r ) ;
2005-06-26 15:05:07 -04:00
}
2006-06-27 14:15:32 -04:00
// Record the match between slide id and these notes
SlidePersistAtom spa = notesSets [ i ] . getSlidePersistAtom ( ) ;
Integer slideId = new Integer ( spa . getSlideIdentifier ( ) ) ;
slideIdToNotes . put ( slideId , new Integer ( i ) ) ;
2005-05-28 01:36:00 -04:00
}
}
2006-03-27 16:35:37 -05:00
2006-06-27 14:15:32 -04:00
// Now, do the same thing for our slides
org . apache . poi . hslf . record . Slide [ ] slidesRecords ;
SlideAtomsSet [ ] slidesSets = new SlideAtomsSet [ 0 ] ;
if ( slidesSLWT = = null ) {
// None
slidesRecords = new org . apache . poi . hslf . record . Slide [ 0 ] ;
} else {
// Match up the records and the SlideAtomSets
slidesSets = slidesSLWT . getSlideAtomsSets ( ) ;
slidesRecords = new org . apache . poi . hslf . record . Slide [ slidesSets . length ] ;
for ( int i = 0 ; i < slidesSets . length ; i + + ) {
// Get the right core record
Record r = getCoreRecordForSAS ( slidesSets [ i ] ) ;
2006-03-27 16:35:37 -05:00
2006-06-27 14:15:32 -04:00
// Ensure it really is a slide record
if ( r instanceof org . apache . poi . hslf . record . Slide ) {
slidesRecords [ i ] = ( org . apache . poi . hslf . record . Slide ) r ;
} else {
System . err . println ( " A Slide SlideAtomSet at " + i + " said its record was at refID " + slidesSets [ i ] . getSlidePersistAtom ( ) . getRefID ( ) + " , but that was actually a " + r ) ;
}
2005-05-28 01:36:00 -04:00
}
}
2006-03-27 16:35:37 -05:00
2006-06-27 14:15:32 -04:00
// Finally, generate model objects for everything
2007-01-09 13:51:29 -05:00
_masters = new SlideMaster [ mainMasterRecords . length ] ;
2006-10-17 14:01:19 -04:00
for ( int i = 0 ; i < _masters . length ; i + + ) {
SlideAtomsSet sas = masterSets [ i ] ;
int sheetNo = sas . getSlidePersistAtom ( ) . getSlideIdentifier ( ) ;
2007-01-09 13:51:29 -05:00
_masters [ i ] = new SlideMaster ( mainMasterRecords [ i ] , sheetNo ) ;
2006-10-17 14:01:19 -04:00
_masters [ i ] . setSlideShow ( this ) ;
}
2006-06-27 14:15:32 -04:00
// Notes first
_notes = new Notes [ notesRecords . length ] ;
2005-05-28 01:36:00 -04:00
for ( int i = 0 ; i < _notes . length ; i + + ) {
2006-06-27 14:15:32 -04:00
_notes [ i ] = new Notes ( notesRecords [ i ] ) ;
2006-04-12 14:48:53 -04:00
_notes [ i ] . setSlideShow ( this ) ;
2005-05-28 01:36:00 -04:00
}
2006-06-27 14:15:32 -04:00
// Then slides
_slides = new Slide [ slidesRecords . length ] ;
2005-05-28 01:36:00 -04:00
for ( int i = 0 ; i < _slides . length ; i + + ) {
2006-06-27 14:15:32 -04:00
SlideAtomsSet sas = slidesSets [ i ] ;
int slideIdentifier = sas . getSlidePersistAtom ( ) . getSlideIdentifier ( ) ;
Integer slideIdentifierI = new Integer ( slideIdentifier ) ;
// Do we have a notes for this?
Notes notes = null ;
if ( slideIdToNotes . containsKey ( slideIdentifierI ) ) {
Integer notesPos = ( Integer ) slideIdToNotes . get ( slideIdentifierI ) ;
notes = _notes [ notesPos . intValue ( ) ] ;
2006-03-18 13:56:26 -05:00
}
2006-06-27 14:15:32 -04:00
// Now, build our slide
_slides [ i ] = new Slide ( slidesRecords [ i ] , notes , sas , slideIdentifier , ( i + 1 ) ) ;
_slides [ i ] . setSlideShow ( this ) ;
2005-05-28 01:36:00 -04:00
}
}
2006-03-26 11:20:08 -05:00
/ * *
* Writes out the slideshow file the is represented by an instance of
* this class
* @param out The OutputStream to write to .
* @throws IOException If there is an unexpected IOException from the passed
* in OutputStream
* /
public void write ( OutputStream out ) throws IOException {
_hslfSlideShow . write ( out ) ;
}
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Accessor Code
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* /
/ * *
* Returns an array of the most recent version of all the interesting
* records
* /
public Record [ ] getMostRecentCoreRecords ( ) { return _mostRecentCoreRecords ; }
/ * *
* Returns an array of all the normal Slides found in the slideshow
* /
public Slide [ ] getSlides ( ) { return _slides ; }
/ * *
* Returns an array of all the normal Notes found in the slideshow
* /
public Notes [ ] getNotes ( ) { return _notes ; }
/ * *
2006-10-17 14:01:19 -04:00
* Returns an array of all the normal Slides found in the slideshow
2006-03-26 11:20:08 -05:00
* /
2006-10-17 14:01:19 -04:00
public SlideMaster [ ] getSlidesMasters ( ) { return _masters ; }
2006-03-26 11:20:08 -05:00
/ * *
2006-04-12 14:48:53 -04:00
* Returns the data of all the pictures attached to the SlideShow
2006-03-26 11:20:08 -05:00
* /
2006-04-12 14:48:53 -04:00
public PictureData [ ] getPictureData ( ) {
2006-03-26 11:20:08 -05:00
return _hslfSlideShow . getPictures ( ) ;
}
/ * *
* Return the current page size
* /
public Dimension getPageSize ( ) {
DocumentAtom docatom = _documentRecord . getDocumentAtom ( ) ;
2006-04-12 14:48:53 -04:00
int pgx = ( int ) docatom . getSlideSizeX ( ) * Shape . POINT_DPI / Shape . MASTER_DPI ;
int pgy = ( int ) docatom . getSlideSizeY ( ) * Shape . POINT_DPI / Shape . MASTER_DPI ;
return new Dimension ( pgx , pgy ) ;
}
/ * *
* Change the current page size
*
* @param pgsize page size ( in points )
* /
public void setPageSize ( Dimension pgsize ) {
DocumentAtom docatom = _documentRecord . getDocumentAtom ( ) ;
docatom . setSlideSizeX ( pgsize . width * Shape . MASTER_DPI / Shape . POINT_DPI ) ;
docatom . setSlideSizeY ( pgsize . height * Shape . MASTER_DPI / Shape . POINT_DPI ) ;
2006-03-26 11:20:08 -05:00
}
/ * *
* Helper method for usermodel : Get the font collection
* /
protected FontCollection getFontCollection ( ) { return _fonts ; }
/ * *
2006-04-12 14:48:53 -04:00
* Helper method for usermodel and model : Get the document record
2006-03-26 11:20:08 -05:00
* /
2006-04-12 14:48:53 -04:00
public Document getDocumentRecord ( ) { return _documentRecord ; }
2006-03-26 11:20:08 -05:00
2006-07-02 12:02:20 -04:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Re - ordering Code
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* /
/ * *
* Re - orders a slide , to a new position .
* @param oldSlideNumer The old slide number ( 1 based )
* @param newSlideNumber The new slide number ( 1 based )
* /
public void reorderSlide ( int oldSlideNumer , int newSlideNumber ) {
// Ensure these numbers are valid
if ( oldSlideNumer < 1 | | newSlideNumber < 1 ) {
throw new IllegalArgumentException ( " Old and new slide numbers must be greater than 0 " ) ;
}
if ( oldSlideNumer > _slides . length | | newSlideNumber > _slides . length ) {
throw new IllegalArgumentException ( " Old and new slide numbers must not exceed the number of slides ( " + _slides . length + " ) " ) ;
}
// Shift the SlideAtomsSet
SlideListWithText slwt = _documentRecord . getSlideSlideListWithText ( ) ;
slwt . repositionSlideAtomsSet (
slwt . getSlideAtomsSets ( ) [ ( oldSlideNumer - 1 ) ] ,
( newSlideNumber - 1 )
) ;
// Re-order the slides
ArrayUtil . arrayMoveWithin ( _slides , ( oldSlideNumer - 1 ) , ( newSlideNumber - 1 ) , 1 ) ;
// Tell the appropriate slides their new numbers
for ( int i = 0 ; i < _slides . length ; i + + ) {
_slides [ i ] . setSlideNumber ( ( i + 1 ) ) ;
}
}
2006-03-26 11:20:08 -05:00
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* Addition Code
* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
* /
2006-03-19 10:59:23 -05:00
/ * *
* Create a blank < code > Slide < / code > .
*
* @return the created < code > Slide < / code >
* @throws IOException
* /
public Slide createSlide ( ) throws IOException {
2006-03-19 12:53:49 -05:00
SlideListWithText slist = null ;
2006-06-27 07:42:29 -04:00
// We need to add the records to the SLWT that deals
// with Slides.
// Add it, if it doesn't exist
slist = _documentRecord . getSlideSlideListWithText ( ) ;
if ( slist = = null ) {
2006-03-19 12:53:49 -05:00
// Need to add a new one
slist = new SlideListWithText ( ) ;
2006-03-26 12:37:04 -05:00
_documentRecord . addSlideListWithText ( slist ) ;
2006-03-19 12:53:49 -05:00
}
2006-03-26 12:37:04 -05:00
// Grab the SlidePersistAtom with the highest Slide Number.
// (Will stay as null if no SlidePersistAtom exists yet in
2006-03-27 16:35:37 -05:00
// the slide, or only master slide's ones do)
2006-03-19 13:09:20 -05:00
SlidePersistAtom prev = null ;
2006-06-27 07:42:29 -04:00
SlideAtomsSet [ ] sas = slist . getSlideAtomsSets ( ) ;
for ( int j = 0 ; j < sas . length ; j + + ) {
SlidePersistAtom spa = sas [ j ] . getSlidePersistAtom ( ) ;
if ( spa . getSlideIdentifier ( ) < 0 ) {
// This is for a master slide
// Odd, since we only deal with the Slide SLWT
} else {
// Must be for a real slide
if ( prev = = null ) { prev = spa ; }
if ( prev . getSlideIdentifier ( ) < spa . getSlideIdentifier ( ) ) {
prev = spa ;
2006-03-26 12:37:04 -05:00
}
}
2006-03-19 13:09:20 -05:00
}
2006-03-26 12:37:04 -05:00
// Set up a new SlidePersistAtom for this slide
2006-03-19 12:53:49 -05:00
SlidePersistAtom sp = new SlidePersistAtom ( ) ;
2006-03-27 16:35:37 -05:00
// Reference is the 1-based index of the slide container in
// the PersistPtr root.
2006-03-19 12:53:49 -05:00
// It always starts with 3 (1 is Document, 2 is MainMaster, 3 is
2006-03-27 16:35:37 -05:00
// the first slide), but quicksaves etc can leave gaps
_highestSheetId + + ;
sp . setRefID ( _highestSheetId ) ;
2006-03-19 12:53:49 -05:00
// First slideId is always 256
sp . setSlideIdentifier ( prev = = null ? 256 : ( prev . getSlideIdentifier ( ) + 1 ) ) ;
2006-03-19 13:09:20 -05:00
// Add this new SlidePersistAtom to the SlideListWithText
2006-03-26 12:37:04 -05:00
slist . addSlidePersistAtom ( sp ) ;
2006-03-19 12:53:49 -05:00
// Create a new Slide
2006-03-27 16:35:37 -05:00
Slide slide = new Slide ( sp . getSlideIdentifier ( ) , sp . getRefID ( ) , _slides . length + 1 ) ;
2006-03-26 14:07:52 -05:00
// Add in to the list of Slides
2006-03-19 12:53:49 -05:00
Slide [ ] s = new Slide [ _slides . length + 1 ] ;
System . arraycopy ( _slides , 0 , s , 0 , _slides . length ) ;
s [ _slides . length ] = slide ;
_slides = s ;
2006-11-28 10:54:39 -05:00
logger . log ( POILogger . INFO , " Added slide " + _slides . length + " with ref " + sp . getRefID ( ) + " and identifier " + sp . getSlideIdentifier ( ) ) ;
2006-03-19 12:53:49 -05:00
2006-03-26 12:37:04 -05:00
// Add the core records for this new Slide to the record tree
2006-03-26 14:07:52 -05:00
org . apache . poi . hslf . record . Slide slideRecord = slide . getSlideRecord ( ) ;
slideRecord . setSheetId ( sp . getRefID ( ) ) ;
2006-03-19 12:53:49 -05:00
int slideRecordPos = _hslfSlideShow . appendRootLevelRecord ( slideRecord ) ;
2006-03-26 12:37:04 -05:00
_records = _hslfSlideShow . getRecords ( ) ;
2006-03-19 12:53:49 -05:00
// Add the new Slide into the PersistPtr stuff
int offset = 0 ;
int slideOffset = 0 ;
PersistPtrHolder ptr = null ;
UserEditAtom usr = null ;
for ( int i = 0 ; i < _records . length ; i + + ) {
Record record = _records [ i ] ;
ByteArrayOutputStream out = new ByteArrayOutputStream ( ) ;
record . writeOut ( out ) ;
// Grab interesting records as they come past
if ( _records [ i ] . getRecordType ( ) = = RecordTypes . PersistPtrIncrementalBlock . typeID ) {
ptr = ( PersistPtrHolder ) _records [ i ] ;
}
if ( _records [ i ] . getRecordType ( ) = = RecordTypes . UserEditAtom . typeID ) {
usr = ( UserEditAtom ) _records [ i ] ;
}
if ( i = = slideRecordPos ) {
slideOffset = offset ;
}
offset + = out . size ( ) ;
}
// Add the new slide into the last PersistPtr
2006-03-26 12:37:04 -05:00
// (Also need to tell it where it is)
2006-03-19 12:53:49 -05:00
slideRecord . setLastOnDiskOffset ( slideOffset ) ;
2006-03-26 12:37:04 -05:00
ptr . addSlideLookup ( sp . getRefID ( ) , slideOffset ) ;
2006-11-28 10:54:39 -05:00
logger . log ( POILogger . INFO , " New slide ended up at " + slideOffset ) ;
2006-03-19 12:53:49 -05:00
// Last view is now of the slide
usr . setLastViewType ( ( short ) UserEditAtom . LAST_VIEW_SLIDE_VIEW ) ;
// All done and added
2006-04-12 14:48:53 -04:00
slide . setSlideShow ( this ) ;
2006-03-19 12:53:49 -05:00
return slide ;
2006-03-19 10:59:23 -05:00
}
2005-05-28 01:36:00 -04:00
2006-03-26 11:20:08 -05:00
/ * *
* Adds a picture to this presentation and returns the associated index .
*
* @param data picture data
* @param format the format of the picture . One of constans defined in the < code > Picture < / code > class .
* @return the index to this picture ( 1 based ) .
* /
2006-09-19 18:37:38 -04:00
public int addPicture ( byte [ ] data , int format ) throws IOException {
2006-03-26 11:20:08 -05:00
byte [ ] uid = PictureData . getChecksum ( data ) ;
EscherContainerRecord bstore ;
int offset = 0 ;
EscherContainerRecord dggContainer = _documentRecord . getPPDrawingGroup ( ) . getDggContainer ( ) ;
bstore = ( EscherContainerRecord ) Shape . getEscherChild ( dggContainer , EscherContainerRecord . BSTORE_CONTAINER ) ;
if ( bstore = = null ) {
bstore = new EscherContainerRecord ( ) ;
bstore . setRecordId ( EscherContainerRecord . BSTORE_CONTAINER ) ;
List child = dggContainer . getChildRecords ( ) ;
for ( int i = 0 ; i < child . size ( ) ; i + + ) {
EscherRecord rec = ( EscherRecord ) child . get ( i ) ;
if ( rec . getRecordId ( ) = = EscherOptRecord . RECORD_ID ) {
child . add ( i , bstore ) ;
i + + ;
}
}
dggContainer . setChildRecords ( child ) ;
} else {
List lst = bstore . getChildRecords ( ) ;
for ( int i = 0 ; i < lst . size ( ) ; i + + ) {
EscherBSERecord bse = ( EscherBSERecord ) lst . get ( i ) ;
if ( Arrays . equals ( bse . getUid ( ) , uid ) ) {
return i + 1 ;
}
offset + = bse . getSize ( ) ;
}
}
2006-09-19 18:37:38 -04:00
PictureData pict = PictureData . create ( format ) ;
pict . setData ( data ) ;
pict . setOffset ( offset ) ;
2006-03-26 11:20:08 -05:00
EscherBSERecord bse = new EscherBSERecord ( ) ;
bse . setRecordId ( EscherBSERecord . RECORD_ID ) ;
bse . setOptions ( ( short ) ( 0x0002 | ( format < < 4 ) ) ) ;
2006-09-19 18:37:38 -04:00
bse . setSize ( pict . getRawData ( ) . length + 8 ) ;
2006-03-26 11:20:08 -05:00
bse . setUid ( uid ) ;
2006-09-19 18:37:38 -04:00
2006-03-26 11:20:08 -05:00
bse . setBlipTypeMacOS ( ( byte ) format ) ;
bse . setBlipTypeWin32 ( ( byte ) format ) ;
2006-09-19 18:37:38 -04:00
if ( format = = Picture . EMF ) bse . setBlipTypeMacOS ( ( byte ) Picture . PICT ) ;
else if ( format = = Picture . WMF ) bse . setBlipTypeMacOS ( ( byte ) Picture . PICT ) ;
else if ( format = = Picture . PICT ) bse . setBlipTypeWin32 ( ( byte ) Picture . WMF ) ;
2006-03-26 11:20:08 -05:00
bse . setRef ( 1 ) ;
bse . setOffset ( offset ) ;
bstore . addChildRecord ( bse ) ;
int count = bstore . getChildRecords ( ) . size ( ) ;
bstore . setOptions ( ( short ) ( ( count < < 4 ) | 0xF ) ) ;
_hslfSlideShow . addPicture ( pict ) ;
return count ;
}
/ * *
* Adds a picture to this presentation and returns the associated index .
*
* @param pict the file containing the image to add
* @param format the format of the picture . One of constans defined in the < code > Picture < / code > class .
* @return the index to this picture ( 1 based ) .
* /
2006-09-19 18:37:38 -04:00
public int addPicture ( File pict , int format ) throws IOException {
2006-03-26 11:20:08 -05:00
int length = ( int ) pict . length ( ) ;
byte [ ] data = new byte [ length ] ;
try {
FileInputStream is = new FileInputStream ( pict ) ;
is . read ( data ) ;
is . close ( ) ;
} catch ( IOException e ) {
throw new RuntimeException ( e ) ;
}
return addPicture ( data , format ) ;
}
2005-05-28 01:36:00 -04:00
}