Hopefully handle the building and using of RichTextRuns correctly. Should include proper handling of the +1 length in the styles (Bug 39177), and shared character/paragraph styles (Bugs 39547 and 38544)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@413912 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
01f4fd56fe
commit
6f7e6cba29
@ -20,6 +20,7 @@
|
|||||||
package org.apache.poi.hslf.model;
|
package org.apache.poi.hslf.model;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
import org.apache.poi.hslf.record.*;
|
import org.apache.poi.hslf.record.*;
|
||||||
import org.apache.poi.hslf.record.StyleTextPropAtom.TextPropCollection;
|
import org.apache.poi.hslf.record.StyleTextPropAtom.TextPropCollection;
|
||||||
@ -92,51 +93,149 @@ public class TextRun
|
|||||||
cStyles = _styleAtom.getCharacterStyles();
|
cStyles = _styleAtom.getCharacterStyles();
|
||||||
}
|
}
|
||||||
|
|
||||||
_rtRuns = new RichTextRun[cStyles.size()];
|
|
||||||
|
|
||||||
// Handle case of no current style, with a default
|
// Handle case of no current style, with a default
|
||||||
if(_rtRuns.length == 0) {
|
if(pStyles.size() == 0 || cStyles.size() == 0) {
|
||||||
_rtRuns = new RichTextRun[1];
|
_rtRuns = new RichTextRun[1];
|
||||||
_rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
|
_rtRuns[0] = new RichTextRun(this, 0, runRawText.length());
|
||||||
} else {
|
} else {
|
||||||
// Build up Rich Text Runs, one for each character style block
|
// Build up Rich Text Runs, one for each
|
||||||
// TODO: Handle case of shared character styles
|
// character/paragraph style pair
|
||||||
|
Vector rtrs = new Vector();
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
int curP = 0;
|
int curP = 0;
|
||||||
int pLenRemain = ((TextPropCollection)pStyles.get(curP)).getCharactersCovered();
|
int curC = 0;
|
||||||
|
int pLenRemain = -1;
|
||||||
|
int cLenRemain = -1;
|
||||||
|
|
||||||
// Build one for each character style
|
// Build one for each run with the same style
|
||||||
for(int i=0; i<_rtRuns.length; i++) {
|
while(pos <= runRawText.length() && curP < pStyles.size() && curC < cStyles.size()) {
|
||||||
// Get the Props to use
|
// Get the Props to use
|
||||||
TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
|
TextPropCollection pProps = (TextPropCollection)pStyles.get(curP);
|
||||||
TextPropCollection cProps = (TextPropCollection)cStyles.get(i);
|
TextPropCollection cProps = (TextPropCollection)cStyles.get(curC);
|
||||||
|
|
||||||
// Get the length to extend over
|
int pLen = pProps.getCharactersCovered();
|
||||||
// (Last run is often 1 char shorter than the cProp claims)
|
int cLen = cProps.getCharactersCovered();
|
||||||
int len = cProps.getCharactersCovered();
|
|
||||||
if(len+pos > runRawText.length()) {
|
|
||||||
len = runRawText.length()-pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the rich text run
|
// Handle new pass
|
||||||
// TODO: Tell the RichTextRun if the styles are shared
|
boolean freshSet = false;
|
||||||
_rtRuns[i] = new RichTextRun(this, pos, len, pProps, cProps, false, false);
|
if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; }
|
||||||
pos += len;
|
if(pLenRemain == -1) { pLenRemain = pLen; }
|
||||||
|
if(cLenRemain == -1) { cLenRemain = cLen; }
|
||||||
|
|
||||||
// See if we need to move onto the next paragraph style
|
// So we know how to build the eventual run
|
||||||
pLenRemain -= len;
|
int runLen = -1;
|
||||||
if(pLenRemain == 0) {
|
boolean pShared = false;
|
||||||
|
boolean cShared = false;
|
||||||
|
|
||||||
|
// Same size, new styles - neither shared
|
||||||
|
if(pLen == cLen && freshSet) {
|
||||||
|
runLen = cLen;
|
||||||
|
pShared = false;
|
||||||
|
cShared = false;
|
||||||
curP++;
|
curP++;
|
||||||
if(curP < pStyles.size()) {
|
curC++;
|
||||||
pLenRemain = ((TextPropCollection)pStyles.get(curP)).getCharactersCovered();
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(pLenRemain < 0) {
|
|
||||||
System.err.println("Paragraph style ran out before character style did! Short by " + (0-pLenRemain) + " characters.");
|
// Wind on
|
||||||
System.err.println("Calling RichTextRun functions is likely to break things - see Bug #38544");
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,21 +311,31 @@ public class TextRun
|
|||||||
ensureStyleAtomPresent();
|
ensureStyleAtomPresent();
|
||||||
|
|
||||||
// Update the text length for its Paragraph and Character stylings
|
// 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 pCol = run._getRawParagraphStyle();
|
||||||
TextPropCollection cCol = run._getRawCharacterStyle();
|
TextPropCollection cCol = run._getRawCharacterStyle();
|
||||||
// Character style covers the new run
|
int newSize = s.length();
|
||||||
cCol.updateTextSize(s.length());
|
|
||||||
// Paragraph might cover other runs to, so remove old size and add new one
|
|
||||||
pCol.updateTextSize( pCol.getCharactersCovered() - run.getLength() + s.length());
|
|
||||||
|
|
||||||
// If we were dealing with the last RichTextRun in the set, then
|
|
||||||
// we need to tell the Character TextPropCollections a size 1 bigger
|
|
||||||
// than it really is
|
|
||||||
// (The Paragraph one will keep the extra 1 length from before)
|
|
||||||
// This extra style length is used to indicate that new text in
|
|
||||||
// the paragraph should go into this set of styling
|
|
||||||
if(runID == _rtRuns.length-1) {
|
if(runID == _rtRuns.length-1) {
|
||||||
cCol.updateTextSize( cCol.getCharactersCovered() + 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
|
// Build up the new text
|
||||||
|
@ -82,6 +82,8 @@ public class RichTextRun
|
|||||||
length = len;
|
length = len;
|
||||||
paragraphStyle = pStyle;
|
paragraphStyle = pStyle;
|
||||||
characterStyle = cStyle;
|
characterStyle = cStyle;
|
||||||
|
sharingParagraphStyle = pShared;
|
||||||
|
sharingCharacterStyle = cShared;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user