You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@poi.apache.org by ni...@apache.org on 2005/11/07 23:24:17 UTC

cvs commit: jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/usermodel RichTextRun.java SlideShow.java

nick        2005/11/07 14:24:17

  Modified:    src/scratchpad/src/org/apache/poi/hslf/model TextRun.java
               src/scratchpad/src/org/apache/poi/hslf/record
                        StyleTextPropAtom.java TextHeaderAtom.java
               src/scratchpad/src/org/apache/poi/hslf/usermodel
                        SlideShow.java
  Added:       src/scratchpad/src/org/apache/poi/hslf/record
                        ParentAwareRecord.java
               src/scratchpad/src/org/apache/poi/hslf/usermodel
                        RichTextRun.java
  Log:
  Lay some of the groundwork for model/usermodel support for rich text
  (note - RichTextRun is not fixed, and method signatures might well change)
  
  Revision  Changes    Path
  1.4       +141 -34   jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java
  
  Index: TextRun.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- TextRun.java	17 Sep 2005 16:44:00 -0000	1.3
  +++ TextRun.java	7 Nov 2005 22:24:12 -0000	1.4
  @@ -19,7 +19,11 @@
   
   package org.apache.poi.hslf.model;
   
  +import java.util.LinkedList;
  +
   import org.apache.poi.hslf.record.*;
  +import org.apache.poi.hslf.record.StyleTextPropAtom.TextPropCollection;
  +import org.apache.poi.hslf.usermodel.RichTextRun;
   import org.apache.poi.util.StringUtil;
   
   /**
  @@ -37,18 +41,17 @@
   	private TextCharsAtom  _charAtom;
   	private StyleTextPropAtom _styleAtom;
   	private boolean _isUnicode;
  +	private RichTextRun[] _rtRuns;
   
   	/**
   	* Constructs a Text Run from a Unicode text block
   	*
   	* @param tha the TextHeaderAtom that defines what's what
   	* @param tca the TextCharsAtom containing the text
  +	* @param sta the StyleTextPropAtom which defines the character stylings
   	*/
   	public TextRun(TextHeaderAtom tha, TextCharsAtom tca, StyleTextPropAtom sta) {
  -		_headerAtom = tha;
  -		_charAtom = tca;
  -		_styleAtom = sta;
  -		_isUnicode = true;
  +		this(tha,null,tca,sta);
   	}
   
   	/**
  @@ -56,12 +59,136 @@
   	*
   	* @param tha the TextHeaderAtom that defines what's what
   	* @param tba the TextBytesAtom containing the text
  +	* @param sta the StyleTextPropAtom which defines the character stylings
   	*/
   	public TextRun(TextHeaderAtom tha, TextBytesAtom tba, StyleTextPropAtom sta) {
  +		this(tha,tba,null,sta);
  +	}
  +	
  +	/**
  +	 * Internal constructor and initializer
  +	 */
  +	private TextRun(TextHeaderAtom tha, TextBytesAtom tba, TextCharsAtom tca, StyleTextPropAtom sta) {
   		_headerAtom = tha;
  -		_byteAtom = tba;
   		_styleAtom = sta;
  -		_isUnicode = false;
  +		if(tba != null) {
  +			_byteAtom = tba;
  +			_isUnicode = false;
  +		} else {
  +			_charAtom = tca;
  +			_isUnicode = true;
  +		}
  +		
  +		// Figure out the rich text runs
  +		// TODO: Handle when paragraph style and character styles don't match up
  +		LinkedList pStyles = new LinkedList();
  +		LinkedList cStyles = new LinkedList();
  +		if(_styleAtom != null) {
  +			pStyles = _styleAtom.getParagraphStyles();
  +			cStyles = _styleAtom.getCharacterStyles();
  +		}
  +		if(pStyles.size() != cStyles.size()) {
  +			throw new RuntimeException("Don't currently handle case of overlapping styles");
  +		}
  +		_rtRuns = new RichTextRun[pStyles.size()];
  +		//for(int i=0; i<)
  +	}
  +	
  +	
  +	// Update methods follow
  +
  +	/**
  +	 * Saves the given string to the records. Doesn't touch the stylings. 
  +	 */
  +	private void storeText(String s) {
  +		if(_isUnicode) {
  +			// The atom can safely convert to unicode
  +			_charAtom.setText(s);
  +		} else {
  +			// Will it fit in a 8 bit atom?
  +			boolean hasMultibyte = StringUtil.hasMultibyte(s);
  +			if(! hasMultibyte) {
  +				// Fine to go into 8 bit atom
  +				byte[] text = new byte[s.length()];
  +				StringUtil.putCompressedUnicode(s,text,0);
  +				_byteAtom.setText(text);
  +			} else {
  +				throw new RuntimeException("Setting of unicode text is currently only possible for Text Runs that are Unicode in the file, sorry. For now, please convert that text to us-ascii and re-try it");
  +			}
  +		}
  +	}
  +	
  +	/**
  +	 * Handles an update to the text stored in one of the Rich Text Runs
  +	 * @param run
  +	 * @param s
  +	 */
  +	public synchronized void changeTextInRichTextRun(RichTextRun run, String s) {
  +		// Figure out which run it is
  +		int runID = -1;
  +		for(int i=0; i<_rtRuns.length; i++) {
  +			if(run.equals(_rtRuns[i])) {
  +				runID = i;
  +			}
  +		}
  +		if(runID == -1) {
  +			throw new IllegalArgumentException("Supplied RichTextRun wasn't from this TextRun");
  +		}
  +		
  +		// Update the text length for its Paragraph and Character stylings
  +		LinkedList pStyles = _styleAtom.getParagraphStyles();
  +		LinkedList cStyles = _styleAtom.getCharacterStyles();
  +		TextPropCollection pCol = (TextPropCollection)pStyles.get(runID);
  +		TextPropCollection cCol = (TextPropCollection)cStyles.get(runID);
  +		pCol.updateTextSize(s.length());
  +		cCol.updateTextSize(s.length());
  +		
  +		// Build up the new text
  +		// As we go through, update the start position for all subsequent runs
  +		// The building relies on the old text still being present
  +		StringBuffer newText = new StringBuffer();
  +		for(int i=0; i<_rtRuns.length; i++) {
  +			// Update start position
  +			if(i > runID) {
  +				_rtRuns[i].updateStartPosition(newText.length());
  +			}
  +			// Grab new text
  +			if(i != runID) {
  +				newText.append(_rtRuns[i].getRawText());
  +			} else {
  +				newText.append(s);
  +			}
  +		}
  +		
  +		// Save the new text
  +		storeText(newText.toString());
  +	}
  +
  +	/**
  +	 * Changes the text, and sets it all to have the same styling
  +	 *  as the the first character has. 
  +	 * If you care about styling, do setText on a RichTextRun instead 
  +	 */
  +	public synchronized void setText(String s) {
  +		// Save the new text to the atoms
  +		storeText(s);
  +
  +		// Now handle record stylings:
  +		//  everthing gets the same style that the first block has
  +		LinkedList pStyles = _styleAtom.getParagraphStyles();
  +		while(pStyles.size() > 1) { pStyles.removeLast(); }
  +		
  +		LinkedList cStyles = _styleAtom.getCharacterStyles();
  +		while(cStyles.size() > 1) { cStyles.removeLast(); }
  +		
  +		TextPropCollection pCol = (TextPropCollection)pStyles.getFirst();
  +		TextPropCollection cCol = (TextPropCollection)cStyles.getFirst();
  +		pCol.updateTextSize(s.length());
  +		cCol.updateTextSize(s.length());
  +		
  +		// Finally, zap and re-do the RichTextRuns
  +		_rtRuns = new RichTextRun[1];
  +		_rtRuns[0] = new RichTextRun(this,0,s.length());
   	}
   
   
  @@ -93,36 +220,16 @@
   			return _byteAtom.getText();
   		}
   	}
  -
  +	
   	/**
  -	 * Changes the text. Chance are, this won't work just yet, because
  -	 *  we also need to update some other bits of the powerpoint file
  -	 *  to match the change in the Text Atom, especially byte offsets
  -	 */
  -	public void setText(String s) {
  -		// If size changed, warn
  -		if(s.length() != getText().length()) {
  -			System.err.println("Warning: Your powerpoint file may no longer readable by powerpoint, as the text run has changed size!");
  -		}
  -
  -		if(_isUnicode) {
  -			// The atom can safely convert to unicode
  -			_charAtom.setText(s);
  -		} else {
  -			// Will it fit in a 8 bit atom?
  -			boolean hasMultibyte = StringUtil.hasMultibyte(s);
  -			if(! hasMultibyte) {
  -				// Fine to go into 8 bit atom
  -				byte[] text = new byte[s.length()];
  -				StringUtil.putCompressedUnicode(s,text,0);
  -				_byteAtom.setText(text);
  -			} else {
  -				throw new RuntimeException("Setting of unicode text is currently only possible for Text Runs that are Unicode in the file, sorry. For now, please convert that text to us-ascii and re-try it");
  -			}
  -		}
  -		
  +	 * Fetch the rich text runs (runs of text with the same styling) that
  +	 *  are contained within this block of text
  +	 * @return
  +	 */
  +	public RichTextRun[] getRichTextRuns() {
  +		return 	_rtRuns;
   	}
  -
  +	
   	/**
   	* Returns the type of the text, from the TextHeaderAtom.
   	* Possible values can be seen from TextHeaderAtom
  
  
  
  1.8       +18 -0     jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java
  
  Index: StyleTextPropAtom.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/record/StyleTextPropAtom.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- StyleTextPropAtom.java	5 Sep 2005 09:34:09 -0000	1.7
  +++ StyleTextPropAtom.java	7 Nov 2005 22:24:12 -0000	1.8
  @@ -64,6 +64,11 @@
   	 */
   	private LinkedList paragraphStyles;
   	public LinkedList getParagraphStyles() { return paragraphStyles; }
  +	/**
  +	 * Updates the link list of TextPropCollections which make up the
  +	 *  paragraph stylings
  +	 */
  +	public void setParagraphStyles(LinkedList ps) { paragraphStyles = ps; }
   	/** 
   	 * The list of all the different character stylings we code for.
   	 * Each entry is a TextPropCollection, which tells you how many
  @@ -72,6 +77,11 @@
   	 */
   	private LinkedList charStyles;
   	public LinkedList getCharacterStyles() { return charStyles; }
  +	/**
  +	 * Updates the link list of TextPropCollections which make up the
  +	 *  character stylings
  +	 */
  +	public void setCharacterStyles(LinkedList cs) { charStyles = cs; }
   
   	/** All the different kinds of paragraph properties we might handle */
   	public TextProp[] paragraphTextPropTypes = new TextProp[] {
  @@ -370,6 +380,14 @@
   			reservedField = -1;
   			textPropList = new LinkedList();
   		}
  +		
  +		/**
  +		 * Update the size of the text that this set of properties
  +		 *  applies to 
  +		 */
  +		public void updateTextSize(int textSize) {
  +			charactersCovered = textSize;
  +		}
   
   		/**
   		 * Writes out to disk the header, and then all the properties
  
  
  
  1.2       +5 -1      jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java
  
  Index: TextHeaderAtom.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/record/TextHeaderAtom.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- TextHeaderAtom.java	28 May 2005 05:36:00 -0000	1.1
  +++ TextHeaderAtom.java	7 Nov 2005 22:24:12 -0000	1.2
  @@ -30,10 +30,11 @@
    * @author Nick Burch
    */
   
  -public class TextHeaderAtom extends RecordAtom
  +public class TextHeaderAtom extends RecordAtom implements ParentAwareRecord
   {
   	private byte[] _header;
   	private static long _type = 3999l;
  +	private RecordContainer parentRecord;
   
   	public static final int TITLE_TYPE = 0;
   	public static final int BODY_TYPE = 1;
  @@ -49,6 +50,9 @@
   
   	public int getTextType() { return textType; }
   	public void setTextType(int type) { textType = type; }
  +	
  +	public RecordContainer getParentRecord() { return parentRecord; }
  +	public void setParentRecord(RecordContainer record) { this.parentRecord = record; } 
   
   	/* *************** record code follows ********************** */
   
  
  
  
  1.1                  jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/record/ParentAwareRecord.java
  
  Index: ParentAwareRecord.java
  ===================================================================
  package org.apache.poi.hslf.record;
  
  /**
   * Interface to define how a record can indicate it cares about what its
   *  parent is, and how it wants to be told which record is its parent.
   * 
   * @author Nick Burch (nick at torchbox dot com)
   */
  public interface ParentAwareRecord {
  	public RecordContainer getParentRecord();
  	public void setParentRecord(RecordContainer parentRecord);
  }
  
  
  
  1.5       +33 -0     jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java
  
  Index: SlideShow.java
  ===================================================================
  RCS file: /home/cvs/jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/usermodel/SlideShow.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- SlideShow.java	17 Sep 2005 16:44:00 -0000	1.4
  +++ SlideShow.java	7 Nov 2005 22:24:15 -0000	1.5
  @@ -27,7 +27,9 @@
   import org.apache.poi.hslf.*;
   import org.apache.poi.hslf.model.*;
   import org.apache.poi.hslf.record.FontCollection;
  +import org.apache.poi.hslf.record.ParentAwareRecord;
   import org.apache.poi.hslf.record.Record;
  +import org.apache.poi.hslf.record.RecordContainer;
   import org.apache.poi.hslf.record.RecordTypes;
   import org.apache.poi.hslf.record.SlideAtom;
   import org.apache.poi.hslf.record.SlideListWithText;
  @@ -78,6 +80,11 @@
       _hslfSlideShow = hslfSlideShow;
   	_records = _hslfSlideShow.getRecords();
   	byte[] _docstream = _hslfSlideShow.getUnderlyingBytes();
  +	
  +	// Handle Parent-aware Reocrds
  +	for(int i=0; i<_records.length; i++) {
  +		handleParentAwareRecords(_records[i]);
  +	}
   
   	// Find the versions of the core records we'll want to use
   	findMostRecentCoreRecords();
  @@ -85,6 +92,32 @@
   	// Build up the model level Slides and Notes
   	buildSlidesAndNotes();
     }
  +  
  +  
  +  /**
  +   * 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);
  +			}
  +		}
  +	  }
  +  }
   
   
     /**
  
  
  
  1.1                  jakarta-poi/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java
  
  Index: RichTextRun.java
  ===================================================================
  
  /* ====================================================================
     Copyright 2002-2004   Apache Software Foundation
  
     Licensed 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
  
         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 org.apache.poi.hslf.model.TextRun;
  
  /**
   * Represents a run of text, all with the same style
   * 
   * TODO: get access to the font/character properties
   *
   * @author Nick Burch
   */
  
  public class RichTextRun
  {
  	/** The TextRun we belong to */
  	private TextRun parentRun;
  	
  	/** Where in the parent TextRun we start from */
  	private int startPos;
  	
  	/** How long a string (in the parent TextRun) we represent */
  	private int length;
  	
  	/** Our paragraph and character style */
  	
  	/**
  	 * Create a new wrapper around a rich text string
  	 * @param parent
  	 * @param startAt
  	 * @param len
  	 */
  	public RichTextRun(TextRun parent, int startAt, int len) {
  		parentRun = parent;
  		startPos = startAt;
  		length = len;
  	}
  	
  	/**
  	 * Fetch the text, in output suitable form
  	 */
  	public String getText() {
  		return parentRun.getText().substring(startPos, startPos+length);
  	}
  	/**
  	 * Fetch the text, in raw storage form
  	 */
  	public String getRawText() {
  		return parentRun.getRawText().substring(startPos, startPos+length);
  	}
  	
  	/**
  	 * Change the text
  	 */
  	public void setText(String text) {
  		length = text.length();
  		parentRun.changeTextInRichTextRun(this,text);
  	}
  	
  	/**
  	 * Tells the RichTextRun its new position in the parent TextRun
  	 * @param startAt
  	 */
  	public void updateStartPosition(int startAt) {
  		startPos = startAt;
  	}
  }
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: poi-dev-unsubscribe@jakarta.apache.org
Mailing List:    http://jakarta.apache.org/site/mail2.html#poi
The Apache Jakarta POI Project: http://jakarta.apache.org/poi/