TextRunpublic class TextRun extends Object This class represents a run of text in a powerpoint document. That
run could be text on a sheet, or text in a note.
It is only a very basic class for now |
Fields Summary |
---|
protected TextHeaderAtom | _headerAtom | protected TextBytesAtom | _byteAtom | protected TextCharsAtom | _charAtom | protected StyleTextPropAtom | _styleAtom | protected boolean | _isUnicode | protected RichTextRun[] | _rtRuns | private SlideShow | slideShow | private Sheet | sheet | private int | shapeId | protected Record[] | _recordsall text run records that follow TextHeaderAtom.
(there can be misc InteractiveInfo, TxInteractiveInfo and other records) |
Constructors Summary |
---|
public TextRun(TextHeaderAtom tha, TextCharsAtom tca, StyleTextPropAtom sta)Constructs a Text Run from a Unicode text block
this(tha,null,tca,sta);
| public TextRun(TextHeaderAtom tha, TextBytesAtom tba, StyleTextPropAtom sta)Constructs a Text Run from a Ascii text block
this(tha,tba,null,sta);
| private TextRun(TextHeaderAtom tha, TextBytesAtom tba, TextCharsAtom tca, StyleTextPropAtom sta)Internal constructor and initializer
_headerAtom = tha;
_styleAtom = sta;
if(tba != null) {
_byteAtom = tba;
_isUnicode = false;
} else {
_charAtom = tca;
_isUnicode = true;
}
String runRawText = getText();
// Figure out the rich text runs
LinkedList pStyles = new LinkedList();
LinkedList cStyles = new LinkedList();
if(_styleAtom != null) {
// Get the style atom to grok itself
_styleAtom.setParentTextSize(runRawText.length());
pStyles = _styleAtom.getParagraphStyles();
cStyles = _styleAtom.getCharacterStyles();
}
// Handle case of no current style, with a default
if(pStyles.size() == 0 || cStyles.size() == 0) {
_rtRuns = new RichTextRun[1];
_rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
} else {
// Build up Rich Text Runs, one for each
// character/paragraph style pair
Vector rtrs = new Vector();
int pos = 0;
int curP = 0;
int curC = 0;
int pLenRemain = -1;
int cLenRemain = -1;
// Build one for each run with the same style
while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
// Get the Props to use
TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
int pLen = pProps.getCharactersCovered();
int cLen = cProps.getCharactersCovered();
// Handle new pass
boolean freshSet = false;
if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
if(pLenRemain == -1) { pLenRemain = pLen; }
if(cLenRemain == -1) { cLenRemain = cLen; }
// So we know how to build the eventual run
int runLen = -1;
boolean pShared = false;
boolean cShared = false;
// Same size, new styles - neither shared
if(pLen == cLen && freshSet) {
runLen = cLen;
pShared = false;
cShared = false;
curP++;
curC++;
pLenRemain = -1;
cLenRemain = -1;
} else {
// Some sharing
// See if we are already in a shared block
if(pLenRemain < pLen) {
// Existing shared p block
pShared = true;
// Do we end with the c block, or either side of it?
if(pLenRemain == cLenRemain) {
// We end at the same time
cShared = false;
runLen = pLenRemain;
curP++;
curC++;
pLenRemain = -1;
cLenRemain = -1;
} else if(pLenRemain < cLenRemain) {
// We end before the c block
cShared = true;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
} else {
// We end after the c block
cShared = false;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
}
} else if(cLenRemain < cLen) {
// Existing shared c block
cShared = true;
// Do we end with the p block, or either side of it?
if(pLenRemain == cLenRemain) {
// We end at the same time
pShared = false;
runLen = cLenRemain;
curP++;
curC++;
pLenRemain = -1;
cLenRemain = -1;
} else if(cLenRemain < pLenRemain) {
// We end before the p block
pShared = true;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
} else {
// We end after the p block
pShared = false;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
}
} else {
// Start of a shared block
if(pLenRemain < cLenRemain) {
// Shared c block
pShared = false;
cShared = true;
runLen = pLenRemain;
curP++;
cLenRemain -= pLenRemain;
pLenRemain = -1;
} else {
// Shared p block
pShared = true;
cShared = false;
runLen = cLenRemain;
curC++;
pLenRemain -= cLenRemain;
cLenRemain = -1;
}
}
}
// Wind on
int prevPos = pos;
pos += runLen;
// Adjust for end-of-run extra 1 length
if(pos > runRawText.length()) {
runLen--;
}
// Save
RichTextRun rtr = new RichTextRun(this, prevPos, runLen, pProps, cProps, pShared, cShared);
rtrs.add(rtr);
}
// Build the array
_rtRuns = new RichTextRun[rtrs.size()];
rtrs.copyInto(_rtRuns);
}
|
Methods Summary |
---|
public synchronized void | changeTextInRichTextRun(org.apache.poi.hslf.usermodel.RichTextRun run, java.lang.String s)Handles an update to the text stored in one of the Rich Text Runs
// 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");
}
// Ensure a StyleTextPropAtom is present, adding if required
ensureStyleAtomPresent();
// Update the text length for its Paragraph and Character stylings
// If it's shared:
// * calculate the new length based on the run's old text
// * this should leave in any +1's for the end of block if needed
// If it isn't shared:
// * reset the length, to the new string's length
// * add on +1 if the last block
// The last run needs its stylings to be 1 longer than the raw
// text is. This is to define the stylings that any new text
// that is added will inherit
TextPropCollection pCol = run._getRawParagraphStyle();
TextPropCollection cCol = run._getRawCharacterStyle();
int newSize = s.length();
if(runID == _rtRuns.length-1) {
newSize++;
}
if(run._isParagraphStyleShared()) {
pCol.updateTextSize( pCol.getCharactersCovered() - run.getLength() + s.length() );
} else {
pCol.updateTextSize(newSize);
}
if(run._isCharacterStyleShared()) {
cCol.updateTextSize( cCol.getCharactersCovered() - run.getLength() + s.length() );
} else {
cCol.updateTextSize(newSize);
}
// 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++) {
int newStartPos = newText.length();
// Build up the new text
if(i != runID) {
// Not the affected run, so keep old text
newText.append(_rtRuns[i].getRawText());
} else {
// Affected run, so use new text
newText.append(s);
}
// Do we need to update the start position of this run?
// (Need to get the text before we update the start pos)
if(i <= runID) {
// Change is after this, so don't need to change start position
} else {
// Change has occured, so update start position
_rtRuns[i].updateStartPosition(newStartPos);
}
}
// Now we can save the new text
storeText(newText.toString());
| public synchronized void | ensureStyleAtomPresent()Ensure a StyleTextPropAtom is present for this run,
by adding if required. Normally for internal TextRun use.
if(_styleAtom != null) {
// All there
return;
}
// Create a new one at the right size
_styleAtom = new StyleTextPropAtom(getRawText().length() + 1);
// Use the TextHeader atom to get at the parent
RecordContainer runAtomsParent = _headerAtom.getParentRecord();
// Add the new StyleTextPropAtom after the TextCharsAtom / TextBytesAtom
Record addAfter = _byteAtom;
if(_byteAtom == null) { addAfter = _charAtom; }
runAtomsParent.addChildAfter(_styleAtom, addAfter);
// Feed this to our sole rich text run
if(_rtRuns.length != 1) {
throw new IllegalStateException("Needed to add StyleTextPropAtom when had many rich text runs");
}
// These are the only styles for now
_rtRuns[0].supplyTextProps(
(TextPropCollection)_styleAtom.getParagraphStyles().get(0),
(TextPropCollection)_styleAtom.getCharacterStyles().get(0),
false,
false
);
| public org.apache.poi.hslf.model.Hyperlink[] | getHyperlinks()Returns the array of all hyperlinks in this text run
return Hyperlink.find(this);
| public java.lang.String | getRawText()Returns the raw text content of the run. This hasn't had any
changes applied to it, and so is probably unlikely to print
out nicely.
if(_isUnicode) {
return _charAtom.getText();
} else {
return _byteAtom.getText();
}
| public org.apache.poi.hslf.usermodel.RichTextRun[] | getRichTextRuns()Fetch the rich text runs (runs of text with the same styling) that
are contained within this block of text
return _rtRuns;
| public int | getRunType()Returns the type of the text, from the TextHeaderAtom.
Possible values can be seen from TextHeaderAtom
return _headerAtom.getTextType();
| protected int | getShapeId()
return shapeId;
| public org.apache.poi.hslf.model.Sheet | getSheet()
return this.sheet;
| public java.lang.String | getText()Returns the text content of the run, which has been made safe
for printing and other use.
String rawText = getRawText();
// PowerPoint seems to store files with \r as the line break
// The messes things up on everything but a Mac, so translate
// them to \n
String text = rawText.replace('\r",'\n");
return text;
| public void | setRunType(int type)Changes the type of the text. Values should be taken
from TextHeaderAtom. No checking is done to ensure you
set this to a valid value!
_headerAtom.setTextType(type);
| protected void | setShapeId(int id)
shapeId = id;
| public void | setSheet(org.apache.poi.hslf.model.Sheet sheet)
this.sheet = sheet;
| public synchronized void | setText(java.lang.String s)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
// Save the new text to the atoms
storeText(s);
RichTextRun fst = _rtRuns[0];
// Finally, zap and re-do the RichTextRuns
for(int i=0; i<_rtRuns.length; i++) { _rtRuns[i] = null; }
_rtRuns = new RichTextRun[1];
_rtRuns[0] = fst;
// Now handle record stylings:
// If there isn't styling
// no change, stays with no styling
// If there is styling:
// everthing gets the same style that the first block has
if(_styleAtom != null) {
LinkedList pStyles = _styleAtom.getParagraphStyles();
while(pStyles.size() > 1) { pStyles.removeLast(); }
LinkedList cStyles = _styleAtom.getCharacterStyles();
while(cStyles.size() > 1) { cStyles.removeLast(); }
_rtRuns[0].setText(s);
} else {
// Recreate rich text run with no styling
_rtRuns[0] = new RichTextRun(this,0,s.length());
}
| private void | storeText(java.lang.String s)Saves the given string to the records. Doesn't touch the stylings.
// Remove a single trailing \n, as there is an implicit one at the
// end of every record
if(s.endsWith("\n")) {
s = s.substring(0, s.length()-1);
}
// Store in the appropriate record
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 {
// Need to swap a TextBytesAtom for a TextCharsAtom
// Build the new TextCharsAtom
_charAtom = new TextCharsAtom();
_charAtom.setText(s);
// Use the TextHeaderAtom to do the swap on the parent
RecordContainer parent = _headerAtom.getParentRecord();
Record[] cr = parent.getChildRecords();
for(int i=0; i<cr.length; i++) {
// Look for TextBytesAtom
if(cr[i].equals(_byteAtom)) {
// Found it, so replace, then all done
cr[i] = _charAtom;
break;
}
}
// Flag the change
_byteAtom = null;
_isUnicode = true;
}
}
| public void | supplySlideShow(org.apache.poi.hslf.usermodel.SlideShow ss)Supply the SlideShow we belong to.
Also passes it on to our child RichTextRuns
slideShow = ss;
if(_rtRuns != null) {
for(int i=0; i<_rtRuns.length; i++) {
_rtRuns[i].supplySlideShow(slideShow);
}
}
|
|