Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hslf » usermodel » [javadoc | source]
    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.usermodel;
   22   
   23   import java.util;
   24   import java.awt.Dimension;
   25   import java.io;
   26   
   27   import org.apache.poi.ddf;
   28   import org.apache.poi.hslf;
   29   import org.apache.poi.hslf.model;
   30   import org.apache.poi.hslf.model.Notes;
   31   import org.apache.poi.hslf.model.Slide;
   32   import org.apache.poi.hslf.record.SlideListWithText;
   33   import org.apache.poi.hslf.record;
   34   import org.apache.poi.hslf.exceptions.CorruptPowerPointFileException;
   35   import org.apache.poi.hslf.exceptions.HSLFException;
   36   import org.apache.poi.util.ArrayUtil;
   37   import org.apache.poi.util.POILogFactory;
   38   import org.apache.poi.util.POILogger;
   39   
   40   /**
   41    * This class is a friendly wrapper on top of the more scary HSLFSlideShow.
   42    *
   43    * TODO:
   44    *  - figure out how to match notes to their correct sheet
   45    *    (will involve understanding DocSlideList and DocNotesList)
   46    *  - handle Slide creation cleaner
   47    * 
   48    * @author Nick Burch
   49    * @author Yegor kozlov
   50    */
   51   
   52   public class SlideShow
   53   {
   54     // What we're based on
   55     private HSLFSlideShow _hslfSlideShow;
   56   
   57     // Low level contents, as taken from HSLFSlideShow
   58     private Record[] _records;
   59   
   60     // Pointers to the most recent versions of the core records
   61     //  (Document, Notes, Slide etc)
   62     private Record[] _mostRecentCoreRecords;
   63     // Lookup between the PersitPtr "sheet" IDs, and the position
   64     //  in the mostRecentCoreRecords array
   65     private Hashtable _sheetIdToCoreRecordsLookup;
   66   
   67     // Records that are interesting
   68     private Document _documentRecord;
   69   
   70     // Friendly objects for people to deal with
   71     private SlideMaster[] _masters;
   72     private TitleMaster[] _titleMasters;
   73     private Slide[] _slides;
   74     private Notes[] _notes;
   75     private FontCollection _fonts;
   76   
   77     // For logging
   78       private POILogger logger = POILogFactory.getLogger(this.getClass());
   79   
   80     
   81     /* ===============================================================
   82      *                       Setup Code
   83      * ===============================================================
   84      */
   85     
   86   
   87     /**
   88      * Constructs a Powerpoint document from the underlying 
   89      * HSLFSlideShow object. Finds the model stuff from this
   90      *
   91      * @param hslfSlideShow the HSLFSlideShow to base on
   92      */
   93     public SlideShow(HSLFSlideShow hslfSlideShow) throws IOException
   94     {
   95   	// Get useful things from our base slideshow
   96       _hslfSlideShow = hslfSlideShow;
   97   	_records = _hslfSlideShow.getRecords();
   98   	
   99   	// Handle Parent-aware Reocrds
  100   	for(int i=0; i<_records.length; i++) {
  101   		handleParentAwareRecords(_records[i]);
  102   	}
  103   
  104   	// Find the versions of the core records we'll want to use
  105   	findMostRecentCoreRecords();
  106   	
  107   	// Build up the model level Slides and Notes
  108   	buildSlidesAndNotes();
  109     }
  110     
  111     /**
  112      * Constructs a new, empty, Powerpoint document.
  113      */
  114     public SlideShow() throws IOException {
  115   	this(new HSLFSlideShow());
  116     }
  117   
  118       /**
  119        * Constructs a Powerpoint document from an input stream.
  120        */
  121       public SlideShow(InputStream inputStream) throws IOException {
  122         this(new HSLFSlideShow(inputStream));
  123       }
  124   
  125     /**
  126      * Find the records that are parent-aware, and tell them
  127      *  who their parent is
  128      */
  129     private void handleParentAwareRecords(Record baseRecord) {
  130   	  // Only need to do something if this is a container record
  131   	  if(baseRecord instanceof RecordContainer) {
  132   		RecordContainer br = (RecordContainer)baseRecord;
  133   		Record[] childRecords = br.getChildRecords();
  134   		
  135   		// Loop over child records, looking for interesting ones
  136   		for(int i=0; i<childRecords.length; i++) {
  137   			Record record = childRecords[i];
  138   			// Tell parent aware records of their parent
  139   			if(record instanceof ParentAwareRecord) {
  140   				((ParentAwareRecord)record).setParentRecord(br);
  141   			}
  142   			// Walk on down for the case of container records
  143   			if(record instanceof RecordContainer) {
  144   				handleParentAwareRecords(record);
  145   			}
  146   		}
  147   	  }
  148     }
  149   
  150   
  151     /**
  152      * Use the PersistPtrHolder entries to figure out what is
  153      *  the "most recent" version of all the core records
  154      *  (Document, Notes, Slide etc), and save a record of them.
  155      * Do this by walking from the oldest PersistPtr to the newest,
  156      *  overwriting any references found along the way with newer ones
  157      */
  158     private void findMostRecentCoreRecords() {
  159   	// To start with, find the most recent in the byte offset domain
  160   	Hashtable mostRecentByBytes = new Hashtable();
  161   	for(int i=0; i<_records.length; i++) {
  162   		if(_records[i] instanceof PersistPtrHolder) {
  163   			PersistPtrHolder pph = (PersistPtrHolder)_records[i];
  164   
  165   			// If we've already seen any of the "slide" IDs for this 
  166   			//  PersistPtr, remove their old positions
  167   			int[] ids = pph.getKnownSlideIDs();
  168   			for(int j=0; j<ids.length; j++) {
  169   				Integer id = new Integer(ids[j]);
  170   				if( mostRecentByBytes.containsKey(id)) {
  171   					mostRecentByBytes.remove(id);
  172   				}	
  173   			}
  174   
  175   			// Now, update the byte level locations with their latest values
  176   			Hashtable thisSetOfLocations = pph.getSlideLocationsLookup();
  177   			for(int j=0; j<ids.length; j++) {
  178   				Integer id = new Integer(ids[j]);
  179   				mostRecentByBytes.put(id, thisSetOfLocations.get(id));
  180   			}
  181   		}
  182   	}
  183   
  184   	// We now know how many unique special records we have, so init
  185   	//  the array
  186   	_mostRecentCoreRecords = new Record[mostRecentByBytes.size()];
  187   	
  188   	// We'll also want to be able to turn the slide IDs into a position
  189   	//  in this array
  190   	_sheetIdToCoreRecordsLookup = new Hashtable();
  191   	int[] allIDs = new int[_mostRecentCoreRecords.length];
  192   	Enumeration ids = mostRecentByBytes.keys();
  193   	for(int i=0; i<allIDs.length; i++) {
  194   		Integer id = (Integer)ids.nextElement();
  195   		allIDs[i] = id.intValue();
  196   	}
  197   	Arrays.sort(allIDs);
  198   	for(int i=0; i<allIDs.length; i++) {
  199   		_sheetIdToCoreRecordsLookup.put(new Integer(allIDs[i]), new Integer(i));
  200   	}
  201   
  202   	// Now convert the byte offsets back into record offsets
  203   	for(int i=0; i<_records.length; i++) {
  204   		if(_records[i] instanceof PositionDependentRecord) {
  205   			PositionDependentRecord pdr = (PositionDependentRecord)_records[i];
  206   			Integer recordAt = new Integer(pdr.getLastOnDiskOffset());
  207   
  208   			// Is it one we care about?
  209   			for(int j=0; j<allIDs.length; j++) {
  210   				Integer thisID = new Integer(allIDs[j]);
  211   				Integer thatRecordAt = (Integer)mostRecentByBytes.get(thisID);
  212   
  213   				if(thatRecordAt.equals(recordAt)) {
  214   					// Bingo. Now, where do we store it?
  215   					Integer storeAtI = 
  216   						(Integer)_sheetIdToCoreRecordsLookup.get(thisID);
  217   					int storeAt = storeAtI.intValue();
  218   					
  219   					// Tell it its Sheet ID, if it cares
  220   					if(pdr instanceof PositionDependentRecordContainer) {
  221   						PositionDependentRecordContainer pdrc = 
  222   							(PositionDependentRecordContainer)_records[i];
  223   						pdrc.setSheetId(thisID.intValue());
  224   					}
  225   					
  226   					// Finally, save the record
  227   					_mostRecentCoreRecords[storeAt] = _records[i];
  228   				}
  229   			}
  230   		}
  231   	}
  232   	
  233   	// Now look for the interesting records in there
  234   	for(int i=0; i<_mostRecentCoreRecords.length; i++) {
  235   		// Check there really is a record at this number
  236   		if(_mostRecentCoreRecords[i] != null) {
  237   			// Find the Document, and interesting things in it
  238   			if(_mostRecentCoreRecords[i].getRecordType() == RecordTypes.Document.typeID) {
  239   				_documentRecord = (Document)_mostRecentCoreRecords[i];
  240   				_fonts = _documentRecord.getEnvironment().getFontCollection();
  241   			}
  242   		} else {
  243   			// No record at this number
  244   			// Odd, but not normally a problem
  245   		}
  246   	}
  247     }
  248     
  249     	/**
  250     	 * For a given SlideAtomsSet, return the core record, based on the refID from the
  251     	 *  SlidePersistAtom
  252     	 */
  253   	private Record getCoreRecordForSAS(SlideAtomsSet sas) {
  254   		SlidePersistAtom spa = sas.getSlidePersistAtom();
  255   		int refID = spa.getRefID();
  256   		return getCoreRecordForRefID(refID);
  257   	}
  258     
  259   	/**
  260      	 * For a given refID (the internal, 0 based numbering scheme), return the
  261   	 *  core record
  262   	 * @param refID the refID
  263   	 */
  264   	private Record getCoreRecordForRefID(int refID) {
  265   		Integer coreRecordId = (Integer)
  266   			_sheetIdToCoreRecordsLookup.get(new Integer(refID));
  267   		if(coreRecordId != null) {
  268   			Record r = _mostRecentCoreRecords[coreRecordId.intValue()];
  269   			return r;
  270   		} else {
  271   			logger.log(POILogger.ERROR, "We tried to look up a reference to a core record, but there was no core ID for reference ID " + refID);
  272   			return null;
  273   		}
  274   	}
  275   
  276     /**
  277      * Build up model level Slide and Notes objects, from the underlying
  278      *  records.
  279      */
  280     private void buildSlidesAndNotes() {
  281   	// Ensure we really found a Document record earlier
  282   	// If we didn't, then the file is probably corrupt
  283   	if(_documentRecord == null) {
  284   		throw new CorruptPowerPointFileException("The PowerPoint file didn't contain a Document Record in its PersistPtr blocks. It is probably corrupt.");
  285   	}
  286   
  287   
  288   	// Fetch the SlideListWithTexts in the most up-to-date Document Record
  289   	//
  290   	// As far as we understand it:
  291   	//  * The first SlideListWithText will contain a SlideAtomsSet
  292   	//     for each of the master slides
  293   	//  * The second SlideListWithText will contain a SlideAtomsSet
  294   	//     for each of the slides, in their current order
  295   	//    These SlideAtomsSets will normally contain text
  296   	//  * The third SlideListWithText (if present), will contain a
  297   	//     SlideAtomsSet for each Notes
  298   	//    These SlideAtomsSets will not normally contain text
  299   	//
  300   	// Having indentified the masters, slides and notes + their orders,
  301   	//  we have to go and find their matching records
  302   	// We always use the latest versions of these records, and use the
  303   	//  SlideAtom/NotesAtom to match them with the StyleAtomSet 
  304   
  305   	SlideListWithText masterSLWT = _documentRecord.getMasterSlideListWithText();
  306   	SlideListWithText slidesSLWT = _documentRecord.getSlideSlideListWithText();
  307   	SlideListWithText notesSLWT  = _documentRecord.getNotesSlideListWithText();
  308   
  309       // Find master slides
  310   	// These can be MainMaster records, but oddly they can also be
  311   	//  Slides or Notes, and possibly even other odd stuff....
  312   	// About the only thing you can say is that the master details are in
  313   	//  the first SLWT.
  314       SlideAtomsSet[] masterSets = new SlideAtomsSet[0];
  315       if (masterSLWT != null){
  316           masterSets = masterSLWT.getSlideAtomsSets();
  317   
  318   		ArrayList mmr = new ArrayList();
  319           ArrayList tmr = new ArrayList();
  320   
  321   		for(int i=0; i<masterSets.length; i++) {
  322   			Record r = getCoreRecordForSAS(masterSets[i]);
  323               SlideAtomsSet sas = masterSets[i];
  324               int sheetNo = sas.getSlidePersistAtom().getSlideIdentifier();
  325   			if(r instanceof org.apache.poi.hslf.record.Slide) {
  326                   TitleMaster master = new TitleMaster((org.apache.poi.hslf.record.Slide)r, sheetNo);
  327                   master.setSlideShow(this);
  328                   tmr.add(master);
  329   			} else if(r instanceof org.apache.poi.hslf.record.MainMaster) {
  330                   SlideMaster master = new SlideMaster((org.apache.poi.hslf.record.MainMaster)r, sheetNo);
  331                   master.setSlideShow(this);
  332                   mmr.add(master);
  333               }
  334   		}
  335   
  336           _masters = new SlideMaster[mmr.size()];
  337           mmr.toArray(_masters);
  338   
  339           _titleMasters = new TitleMaster[tmr.size()];
  340           tmr.toArray(_titleMasters);
  341   
  342       }
  343   
  344   
  345   	// Having sorted out the masters, that leaves the notes and slides
  346   
  347   
  348   	// Start by finding the notes records to go with the entries in
  349   	//  notesSLWT
  350   	org.apache.poi.hslf.record.Notes[] notesRecords;
  351   	SlideAtomsSet[] notesSets = new SlideAtomsSet[0];
  352   	Hashtable slideIdToNotes = new Hashtable();
  353   	if(notesSLWT == null) {
  354   		// None
  355   		notesRecords = new org.apache.poi.hslf.record.Notes[0]; 
  356   	} else {
  357   		// Match up the records and the SlideAtomSets
  358   		notesSets = notesSLWT.getSlideAtomsSets();
  359   		ArrayList notesRecordsL = new ArrayList();
  360   		for(int i=0; i<notesSets.length; i++) {
  361   			// Get the right core record
  362   			Record r = getCoreRecordForSAS(notesSets[i]);
  363   
  364   			// Ensure it really is a notes record
  365   			if(r instanceof org.apache.poi.hslf.record.Notes) {
  366                   org.apache.poi.hslf.record.Notes notesRecord = (org.apache.poi.hslf.record.Notes)r;
  367   				notesRecordsL.add( notesRecord );
  368   
  369   				// Record the match between slide id and these notes
  370                   SlidePersistAtom spa = notesSets[i].getSlidePersistAtom();
  371                   Integer slideId = new Integer(spa.getSlideIdentifier());
  372                   slideIdToNotes.put(slideId, new Integer(i));
  373   			} else {
  374   				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);
  375   			}
  376   		}
  377   		notesRecords = new org.apache.poi.hslf.record.Notes[notesRecordsL.size()];
  378   		notesRecords = (org.apache.poi.hslf.record.Notes[])
  379   			notesRecordsL.toArray(notesRecords);
  380   	}
  381   	
  382   	// Now, do the same thing for our slides
  383   	org.apache.poi.hslf.record.Slide[] slidesRecords;
  384   	SlideAtomsSet[] slidesSets = new SlideAtomsSet[0];
  385   	if(slidesSLWT == null) {
  386   		// None
  387   		slidesRecords = new org.apache.poi.hslf.record.Slide[0]; 
  388   	} else {
  389   		// Match up the records and the SlideAtomSets
  390   		slidesSets = slidesSLWT.getSlideAtomsSets();
  391   		slidesRecords = new org.apache.poi.hslf.record.Slide[slidesSets.length];
  392   		for(int i=0; i<slidesSets.length; i++) {
  393   			// Get the right core record
  394   			Record r = getCoreRecordForSAS(slidesSets[i]);
  395   			
  396   			// Ensure it really is a slide record
  397   			if(r instanceof org.apache.poi.hslf.record.Slide) {
  398   				slidesRecords[i] = (org.apache.poi.hslf.record.Slide)r;
  399   			} else {
  400   				logger.log(POILogger.ERROR, "A Slide SlideAtomSet at " + i + " said its record was at refID " + slidesSets[i].getSlidePersistAtom().getRefID() + ", but that was actually a " + r);
  401   			}
  402   		}
  403   	}
  404   	
  405   	// Finally, generate model objects for everything
  406   	// Notes first
  407   	_notes = new Notes[notesRecords.length];
  408   	for(int i=0; i<_notes.length; i++) {
  409   		_notes[i] = new Notes(notesRecords[i]);
  410   		_notes[i].setSlideShow(this);
  411   	}
  412   	// Then slides
  413   	_slides = new Slide[slidesRecords.length];
  414   	for(int i=0; i<_slides.length; i++) {
  415   		SlideAtomsSet sas = slidesSets[i];
  416   		int slideIdentifier = sas.getSlidePersistAtom().getSlideIdentifier();
  417   
  418   		// Do we have a notes for this?
  419   		Notes notes = null;
  420           //Slide.SlideAtom.notesId references the corresponding notes slide. 0 if slide has no notes.
  421           int noteId = slidesRecords[i].getSlideAtom().getNotesID();
  422           if (noteId != 0){
  423               Integer notesPos = (Integer)slideIdToNotes.get(new Integer(noteId));
  424               if (notesPos != null) notes = _notes[notesPos.intValue()];
  425               else logger.log(POILogger.ERROR, "Notes not found for noteId=" + noteId);
  426           }
  427   
  428   		// Now, build our slide
  429   		_slides[i] = new Slide(slidesRecords[i], notes, sas, slideIdentifier, (i+1));
  430   		_slides[i].setSlideShow(this);
  431   	}
  432     }
  433   
  434     /**
  435      * Writes out the slideshow file the is represented by an instance of
  436      *  this class
  437      * @param out The OutputStream to write to.
  438      *  @throws IOException If there is an unexpected IOException from the passed
  439      *            in OutputStream
  440      */
  441      public void write(OutputStream out) throws IOException {
  442   	_hslfSlideShow.write(out);
  443      }
  444   
  445   
  446      /* ===============================================================
  447       *                       Accessor Code
  448       * ===============================================================
  449       */
  450      
  451   
  452   	/**
  453   	 * Returns an array of the most recent version of all the interesting
  454   	 *  records
  455   	 */
  456   	public Record[] getMostRecentCoreRecords() { return _mostRecentCoreRecords; }
  457   
  458   	/**
  459   	 * Returns an array of all the normal Slides found in the slideshow
  460   	 */
  461   	public Slide[] getSlides() { return _slides; }
  462   
  463   	/**
  464   	 * Returns an array of all the normal Notes found in the slideshow
  465   	 */
  466   	public Notes[] getNotes() { return _notes; }
  467   
  468   	/**
  469        * Returns an array of all the normal Slide Masters found in the slideshow
  470   	 */
  471       public SlideMaster[] getSlidesMasters() { return _masters; }
  472   
  473       /**
  474        * Returns an array of all the normal Title Masters found in the slideshow
  475        */
  476       public TitleMaster[] getTitleMasters() { return _titleMasters; }
  477   	/**
  478   	 * Returns the data of all the pictures attached to the SlideShow
  479   	 */
  480   	public PictureData[] getPictureData() {
  481   		return _hslfSlideShow.getPictures();
  482   	}
  483   
  484       /**
  485        * Returns the data of all the embedded OLE object in the SlideShow
  486        */
  487       public ObjectData[] getEmbeddedObjects() {
  488           return _hslfSlideShow.getEmbeddedObjects();
  489       }
  490   
  491       /**
  492        * Returns the data of all the embedded sounds in the SlideShow
  493        */
  494       public SoundData[] getSoundData() {
  495           return SoundData.find(_documentRecord);
  496       }
  497   
  498   	/**
  499   	 * Return the current page size
  500   	 */
  501   	public Dimension getPageSize(){
  502   		DocumentAtom docatom = _documentRecord.getDocumentAtom();
  503   		int pgx = (int)docatom.getSlideSizeX()*Shape.POINT_DPI/Shape.MASTER_DPI;
  504   		int pgy = (int)docatom.getSlideSizeY()*Shape.POINT_DPI/Shape.MASTER_DPI;
  505   		return new Dimension(pgx, pgy);
  506   	}
  507   	
  508   	/**
  509   	 * Change the current page size
  510   	 * 
  511   	 * @param pgsize page size (in points)
  512   	 */
  513   	public void setPageSize(Dimension pgsize){
  514   		DocumentAtom docatom = _documentRecord.getDocumentAtom();
  515   		docatom.setSlideSizeX(pgsize.width*Shape.MASTER_DPI/Shape.POINT_DPI);
  516   		docatom.setSlideSizeY(pgsize.height*Shape.MASTER_DPI/Shape.POINT_DPI);
  517   	}
  518   	
  519   	/**
  520   	 * Helper method for usermodel: Get the font collection
  521   	 */
  522   	protected FontCollection getFontCollection() { return _fonts; }
  523   	/**
  524   	 * Helper method for usermodel and model: Get the document record
  525   	 */
  526   	public Document getDocumentRecord() { return _documentRecord; }
  527   
  528   	
  529   	/* ===============================================================
  530   	 *                       Re-ordering Code
  531   	 * ===============================================================
  532   	 */
  533   	   
  534   	
  535   	/**
  536   	 * Re-orders a slide, to a new position.
  537   	 * @param oldSlideNumer The old slide number (1 based)
  538   	 * @param newSlideNumber The new slide number (1 based)
  539   	 */
  540   	public void reorderSlide(int oldSlideNumer, int newSlideNumber) {
  541   		// Ensure these numbers are valid
  542   		if(oldSlideNumer < 1 || newSlideNumber < 1) {
  543   			throw new IllegalArgumentException("Old and new slide numbers must be greater than 0");
  544   		}
  545   		if(oldSlideNumer > _slides.length || newSlideNumber > _slides.length) {
  546   			throw new IllegalArgumentException("Old and new slide numbers must not exceed the number of slides (" + _slides.length + ")");
  547   		}
  548   		
  549   		// Shift the SlideAtomsSet
  550   		SlideListWithText slwt = _documentRecord.getSlideSlideListWithText(); 
  551   		slwt.repositionSlideAtomsSet( 
  552   				slwt.getSlideAtomsSets()[(oldSlideNumer-1)],
  553   				(newSlideNumber-1)
  554   		);
  555   		
  556   		// Re-order the slides
  557   		ArrayUtil.arrayMoveWithin(_slides, (oldSlideNumer-1), (newSlideNumber-1), 1);
  558   		
  559   		// Tell the appropriate slides their new numbers
  560   		for(int i=0; i<_slides.length; i++) {
  561   			_slides[i].setSlideNumber( (i+1) );
  562   		}
  563   	}
  564   
  565   	/* ===============================================================
  566   	 *                       Addition Code
  567   	 * ===============================================================
  568   	 */
  569   	   
  570   
  571   	/**
  572   	 * Create a blank <code>Slide</code>.
  573   	 *
  574   	 * @return  the created <code>Slide</code>
  575   	 * @throws IOException
  576   	 */
  577     	public Slide createSlide() throws IOException {
  578     		SlideListWithText slist = null;
  579   
  580     		// We need to add the records to the SLWT that deals
  581     		//  with Slides.
  582     		// Add it, if it doesn't exist
  583     		slist = _documentRecord.getSlideSlideListWithText();
  584     		if(slist == null) {
  585     			// Need to add a new one
  586     			slist = new SlideListWithText();
  587     			_documentRecord.addSlideListWithText(slist);
  588     		}
  589   
  590     		// Grab the SlidePersistAtom with the highest Slide Number.
  591     		// (Will stay as null if no SlidePersistAtom exists yet in
  592     		//  the slide, or only master slide's ones do)
  593     		SlidePersistAtom prev = null;
  594   		SlideAtomsSet[] sas = slist.getSlideAtomsSets();
  595     		for(int j=0; j<sas.length; j++) {
  596     			SlidePersistAtom spa = sas[j].getSlidePersistAtom();
  597     			if(spa.getSlideIdentifier() < 0) {
  598     				// This is for a master slide
  599     				// Odd, since we only deal with the Slide SLWT
  600     			} else {
  601   				// Must be for a real slide
  602     				if(prev == null) { prev = spa; }
  603     				if(prev.getSlideIdentifier() < spa.getSlideIdentifier()) {
  604     					prev = spa;
  605     				}
  606     			}
  607     		}
  608   
  609     		// Set up a new  SlidePersistAtom for this slide
  610     		SlidePersistAtom sp = new SlidePersistAtom();
  611   
  612     		// First slideId is always 256
  613     		sp.setSlideIdentifier(prev == null ? 256 : (prev.getSlideIdentifier() + 1));
  614   
  615     		// Add this new SlidePersistAtom to the SlideListWithText
  616     		slist.addSlidePersistAtom(sp);
  617   
  618   
  619     		// Create a new Slide
  620     		Slide slide = new Slide(sp.getSlideIdentifier(), sp.getRefID(), _slides.length+1);
  621           slide.setSlideShow(this);
  622           slide.onCreate();
  623   
  624     		// Add in to the list of Slides
  625     		Slide[] s = new Slide[_slides.length+1];
  626     		System.arraycopy(_slides, 0, s, 0, _slides.length);
  627     		s[_slides.length] = slide;
  628     		_slides = s;
  629     		logger.log(POILogger.INFO, "Added slide " + _slides.length + " with ref " + sp.getRefID() + " and identifier " + sp.getSlideIdentifier());
  630   
  631     		// Add the core records for this new Slide to the record tree
  632     		org.apache.poi.hslf.record.Slide slideRecord = slide.getSlideRecord();
  633     		int slideRecordPos = _hslfSlideShow.appendRootLevelRecord(slideRecord);
  634     		_records = _hslfSlideShow.getRecords();
  635   
  636   
  637     		// Add the new Slide into the PersistPtr stuff
  638     		int offset = 0;
  639     		int slideOffset = 0;
  640     		PersistPtrHolder ptr = null;
  641     		UserEditAtom usr = null;
  642     		for (int i = 0; i < _records.length; i++) {
  643     			Record record = _records[i];
  644     			ByteArrayOutputStream out = new ByteArrayOutputStream();
  645     			record.writeOut(out);
  646   
  647     			// Grab interesting records as they come past
  648     			if(_records[i].getRecordType() == RecordTypes.PersistPtrIncrementalBlock.typeID){
  649     				ptr = (PersistPtrHolder)_records[i];
  650     			}
  651     			if(_records[i].getRecordType() == RecordTypes.UserEditAtom.typeID) {
  652     				usr = (UserEditAtom)_records[i];
  653     			}
  654   
  655     			if(i == slideRecordPos) {
  656     				slideOffset = offset;
  657     			}
  658     			offset += out.size();
  659     		}
  660   
  661           // persist ID is UserEditAtom.maxPersistWritten + 1
  662           int psrId = usr.getMaxPersistWritten() + 1;
  663           sp.setRefID(psrId);
  664           slideRecord.setSheetId(psrId);
  665   
  666           // Last view is now of the slide
  667           usr.setLastViewType((short)UserEditAtom.LAST_VIEW_SLIDE_VIEW);
  668           usr.setMaxPersistWritten(psrId);    //increment the number of persit objects
  669   
  670   		// Add the new slide into the last PersistPtr
  671     		// (Also need to tell it where it is)
  672   		slideRecord.setLastOnDiskOffset(slideOffset);
  673   		ptr.addSlideLookup(sp.getRefID(), slideOffset);
  674   		logger.log(POILogger.INFO, "New slide ended up at " + slideOffset);
  675   
  676     		// All done and added
  677     		return slide;
  678   	}
  679   
  680   
  681       /**
  682        * Adds a picture to this presentation and returns the associated index.
  683        *
  684        * @param data      picture data
  685        * @param format    the format of the picture.  One of constans defined in the <code>Picture</code> class.
  686        * @return          the index to this picture (1 based).
  687        */
  688       public int addPicture(byte[] data, int format) throws IOException {
  689           byte[] uid = PictureData.getChecksum(data);
  690   
  691           EscherContainerRecord bstore;
  692           int offset = 0;
  693   
  694           EscherContainerRecord dggContainer = _documentRecord.getPPDrawingGroup().getDggContainer();
  695           bstore = (EscherContainerRecord)Shape.getEscherChild(dggContainer, EscherContainerRecord.BSTORE_CONTAINER);
  696           if (bstore == null){
  697               bstore = new EscherContainerRecord();
  698               bstore.setRecordId( EscherContainerRecord.BSTORE_CONTAINER);
  699   
  700               List child = dggContainer.getChildRecords();
  701               for ( int i = 0; i < child.size(); i++ ) {
  702                   EscherRecord rec = (EscherRecord)child.get(i);
  703                   if (rec.getRecordId() == EscherOptRecord.RECORD_ID){
  704                       child.add(i, bstore);
  705                       i++;
  706                   }
  707               }
  708               dggContainer.setChildRecords(child);
  709           } else {
  710               List lst = bstore.getChildRecords();
  711               for ( int i = 0; i < lst.size(); i++ ) {
  712                   EscherBSERecord bse = (EscherBSERecord) lst.get(i);
  713                   if (Arrays.equals(bse.getUid(), uid)){
  714                       return i + 1;
  715                   }
  716                   offset += bse.getSize();
  717                }
  718           }
  719   
  720           PictureData pict = PictureData.create(format);
  721           pict.setData(data);
  722           pict.setOffset(offset);
  723   
  724           EscherBSERecord bse = new EscherBSERecord();
  725           bse.setRecordId(EscherBSERecord.RECORD_ID);
  726           bse.setOptions( (short) ( 0x0002 | ( format << 4 ) ) );
  727           bse.setSize(pict.getRawData().length + 8);
  728           bse.setUid(uid);
  729   
  730           bse.setBlipTypeMacOS((byte)format);
  731           bse.setBlipTypeWin32((byte)format);
  732   
  733           if (format == Picture.EMF) bse.setBlipTypeMacOS((byte)Picture.PICT);
  734           else if (format == Picture.WMF) bse.setBlipTypeMacOS((byte)Picture.PICT);
  735           else if (format == Picture.PICT) bse.setBlipTypeWin32((byte)Picture.WMF);
  736   
  737           bse.setRef(0);
  738           bse.setOffset(offset);
  739   
  740           bstore.addChildRecord(bse);
  741           int count = bstore.getChildRecords().size();
  742           bstore.setOptions((short)( (count << 4) | 0xF ));
  743   
  744           _hslfSlideShow.addPicture(pict);
  745   
  746           return count;
  747       }
  748   
  749       /**
  750        * Adds a picture to this presentation and returns the associated index.
  751        *
  752        * @param pict       the file containing the image to add
  753        * @param format    the format of the picture.  One of constans defined in the <code>Picture</code> class.
  754        * @return          the index to this picture (1 based).
  755        */
  756       public int addPicture(File pict, int format) throws IOException {
  757           int length = (int)pict.length();
  758           byte[] data = new byte[length];
  759           try {
  760               FileInputStream is = new FileInputStream(pict);
  761               is.read(data);
  762               is.close();
  763           } catch (IOException e){
  764               throw new HSLFException(e);
  765           }
  766           return addPicture(data, format);
  767       }
  768   
  769       /**
  770        * Add a font in this presentation
  771        *
  772        * @param font the font to add
  773        * @return 0-based index of the font
  774        */
  775       public int addFont(PPFont font) {
  776           FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection();
  777           int idx = fonts.getFontIndex(font.getFontName());
  778           if(idx == -1){
  779               idx = fonts.addFont(font.getFontName(), font.getCharSet(), font.getFontFlags(), font.getFontType(), font.getPitchAndFamily());
  780           }
  781           return idx;
  782       }
  783   
  784       /**
  785        * Get a font by index
  786        *
  787        * @param idx 0-based index of the font
  788        * @return of an instance of <code>PPFont</code> or <code>null</code> if not found
  789        */
  790       public PPFont getFont(int idx) {
  791           PPFont font = null;
  792           FontCollection fonts = getDocumentRecord().getEnvironment().getFontCollection();
  793           Record[] ch = fonts.getChildRecords();
  794           for (int i = 0; i < ch.length; i++) {
  795               if(ch[i] instanceof FontEntityAtom) {
  796                   FontEntityAtom atom = (FontEntityAtom)ch[i];
  797                   if(atom.getFontIndex() == idx){
  798                       font = new PPFont(atom);
  799                       break;
  800                   }
  801               }
  802           }
  803           return font;
  804       }
  805   
  806       /**
  807        * get the number of fonts in the presentation
  808        *
  809        * @return number of fonts
  810        */
  811       public int getNumberOfFonts() {
  812           return getDocumentRecord().getEnvironment().getFontCollection().getNumberOfFonts();
  813       }
  814   }

Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache » poi » hslf » usermodel » [javadoc | source]