avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont, see Bugzilla 50258
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1036599 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
9b52b521cf
commit
09f53282ec
@ -34,6 +34,7 @@
|
||||
|
||||
<changes>
|
||||
<release version="3.8-beta1" date="2010-??-??">
|
||||
<action dev="poi-developers" type="fix">50258 - avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont</action>
|
||||
<action dev="poi-developers" type="fix">50154 - Allow white spaces and unicode in OPC relationship targets </action>
|
||||
<action dev="poi-developers" type="fix">50113 - Remove cell from Calculation Chain after setting cell type to blank </action>
|
||||
<action dev="poi-developers" type="fix">49966 - Ensure that XSSFRow#removeCell cleares calculation chain entries </action>
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
package org.apache.poi.xssf.usermodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.*;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.Matcher;
|
||||
|
||||
@ -132,7 +132,6 @@ public class XSSFRichTextString implements RichTextString {
|
||||
* @param endIndex The end index to apply to font to (exclusive)
|
||||
* @param font The index of the font to use.
|
||||
*/
|
||||
@SuppressWarnings("deprecation") //YK: getXYZArray() array accessors are deprecated in xmlbeans with JDK 1.5 support
|
||||
public void applyFont(int startIndex, int endIndex, Font font) {
|
||||
if (startIndex > endIndex)
|
||||
throw new IllegalArgumentException("Start index must be less than end index.");
|
||||
@ -148,56 +147,15 @@ public class XSSFRichTextString implements RichTextString {
|
||||
}
|
||||
|
||||
String text = getString();
|
||||
|
||||
XSSFFont xssfFont = (XSSFFont)font;
|
||||
ArrayList<CTRElt> runs = new ArrayList<CTRElt>();
|
||||
|
||||
CTRElt[] r = st.getRArray();
|
||||
int pos = 0;
|
||||
for (int i = 0; i < r.length; i++) {
|
||||
int rStart = pos;
|
||||
String t = r[i].getT();
|
||||
int rEnd = rStart + t.length();
|
||||
TreeMap<Integer, CTRPrElt> formats = getFormatMap(st);
|
||||
CTRPrElt fmt = CTRPrElt.Factory.newInstance();
|
||||
setRunAttributes(xssfFont.getCTFont(), fmt);
|
||||
applyFont(formats, startIndex, endIndex, fmt);
|
||||
|
||||
if(rEnd <= startIndex) {
|
||||
runs.add(r[i]);
|
||||
pos += r[i].getT().length();
|
||||
}
|
||||
else if (startIndex > rStart && startIndex < rEnd){
|
||||
CTRElt c = (CTRElt)r[i].copy();
|
||||
String txt = text.substring(rStart, startIndex);
|
||||
c.setT(txt);
|
||||
runs.add(c);
|
||||
pos += txt.length();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
CTRElt rt = CTRElt.Factory.newInstance();
|
||||
String txt = text.substring(startIndex, endIndex);
|
||||
rt.setT(txt);
|
||||
CTRPrElt pr = rt.addNewRPr();
|
||||
setRunAttributes(xssfFont.getCTFont(), pr);
|
||||
runs.add(rt);
|
||||
pos += txt.length();
|
||||
|
||||
for (int i = 0; i < r.length; i++) {
|
||||
int rStart = pos;
|
||||
String t = r[i].getT();
|
||||
int rEnd = Math.min(rStart + t.length(), text.length());
|
||||
|
||||
if (endIndex < rEnd){
|
||||
CTRElt c = (CTRElt)r[i].copy();
|
||||
txt = text.substring(rStart, rEnd);
|
||||
c.setT(txt);
|
||||
runs.add(c);
|
||||
pos += txt.length();
|
||||
preserveSpaces(c.xgetT());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
st.setRArray(runs.toArray(new CTRElt[runs.size()]));
|
||||
CTRst newSt = buildCTRst(text, formats);
|
||||
st.set(newSt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,17 +163,8 @@ public class XSSFRichTextString implements RichTextString {
|
||||
* @param font The font to use.
|
||||
*/
|
||||
public void applyFont(Font font) {
|
||||
if(st.sizeOfRArray() == 0 && st.isSetT()) {
|
||||
CTRElt r = st.addNewR();
|
||||
r.setT(st.getT());
|
||||
setRunAttributes(((XSSFFont)font).getCTFont(), r.addNewRPr());
|
||||
st.unsetT();
|
||||
} else {
|
||||
CTRElt r = CTRElt.Factory.newInstance();
|
||||
r.setT(getString());
|
||||
setRunAttributes(((XSSFFont)font).getCTFont(), r.addNewRPr());
|
||||
st.setRArray(new CTRElt[]{r});
|
||||
}
|
||||
String text = getString();
|
||||
applyFont(0, text.length(), font);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -231,7 +180,8 @@ public class XSSFRichTextString implements RichTextString {
|
||||
} else {
|
||||
font = styles.getFontAt(fontIndex);
|
||||
}
|
||||
applyFont(font);
|
||||
String text = getString();
|
||||
applyFont(0, text.length(), font);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,9 +245,7 @@ public class XSSFRichTextString implements RichTextString {
|
||||
*/
|
||||
public void clearFormatting() {
|
||||
String text = getString();
|
||||
while (st.sizeOfRArray() > 0) {
|
||||
st.removeR(st.sizeOfRArray()-1);
|
||||
}
|
||||
st.setRArray(null);
|
||||
st.setT(text);
|
||||
}
|
||||
|
||||
@ -531,4 +479,62 @@ public class XSSFRichTextString implements RichTextString {
|
||||
buf.append(value.substring(idx));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
void applyFont(TreeMap<Integer, CTRPrElt> formats, int startIndex, int endIndex, CTRPrElt fmt) {
|
||||
// delete format runs that fit between startIndex and endIndex
|
||||
// runs intersecting startIndex and endIndex remain
|
||||
int runStartIdx = 0;
|
||||
for (Iterator<Integer> it = formats.keySet().iterator(); it.hasNext();) {
|
||||
int runEndIdx = it.next();
|
||||
if (runStartIdx >= startIndex && runEndIdx < endIndex) {
|
||||
it.remove();
|
||||
}
|
||||
runStartIdx = runEndIdx;
|
||||
}
|
||||
|
||||
if(startIndex > 0 && !formats.containsKey(startIndex)) {
|
||||
Map.Entry<Integer, CTRPrElt> he = formats.higherEntry(startIndex); //TODO TreeMap#higherEntry is JDK 1.6 only!
|
||||
if(he != null) formats.put(startIndex, he.getValue());
|
||||
}
|
||||
formats.put(endIndex, fmt);
|
||||
|
||||
// assure that the range [startIndex, endIndex] consists if a single run
|
||||
// there can be two or three runs depending whether startIndex or endIndex
|
||||
// intersected existing format runs
|
||||
SortedMap<Integer, CTRPrElt> sub = formats.subMap(startIndex, endIndex);
|
||||
while(sub.size() > 1) sub.remove(sub.lastKey());
|
||||
}
|
||||
|
||||
TreeMap<Integer, CTRPrElt> getFormatMap(CTRst entry){
|
||||
int length = 0;
|
||||
TreeMap<Integer, CTRPrElt> formats = new TreeMap<Integer, CTRPrElt>();
|
||||
for (CTRElt r : entry.getRArray()) {
|
||||
String txt = r.getT();
|
||||
CTRPrElt fmt = r.getRPr();
|
||||
|
||||
length += txt.length();
|
||||
formats.put(length, fmt);
|
||||
}
|
||||
return formats;
|
||||
}
|
||||
|
||||
CTRst buildCTRst(String text, TreeMap<Integer, CTRPrElt> formats){
|
||||
if(text.length() != formats.lastKey()) {
|
||||
throw new IllegalArgumentException("Text length was " + text.length() +
|
||||
" but the last format index was " + formats.lastKey());
|
||||
}
|
||||
CTRst st = CTRst.Factory.newInstance();
|
||||
int runStartIdx = 0;
|
||||
for (Iterator<Integer> it = formats.keySet().iterator(); it.hasNext();) {
|
||||
int runEndIdx = it.next();
|
||||
CTRElt run = st.addNewR();
|
||||
String fragment = text.substring(runStartIdx, runEndIdx);
|
||||
run.setT(fragment);
|
||||
preserveSpaces(run.xgetT());
|
||||
CTRPrElt fmt = formats.get(runEndIdx);
|
||||
if(fmt != null) run.setRPr(fmt);
|
||||
runStartIdx = runEndIdx;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,9 @@ import junit.framework.TestCase;
|
||||
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRst;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXstring;
|
||||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRPrElt;
|
||||
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Tests functionality of the XSSFRichTextRun object
|
||||
@ -53,23 +56,27 @@ public final class TestXSSFRichTextString extends TestCase {
|
||||
rt.append("4567");
|
||||
rt.append("89");
|
||||
|
||||
assertEquals("123456789", rt.getString());
|
||||
|
||||
XSSFFont font1 = new XSSFFont();
|
||||
font1.setBold(true);
|
||||
|
||||
rt.applyFont(2, 5, font1);
|
||||
|
||||
assertEquals(5, rt.numFormattingRuns());
|
||||
assertEquals(4, rt.numFormattingRuns());
|
||||
assertEquals(0, rt.getIndexOfFormattingRun(0));
|
||||
assertEquals(2, rt.getLengthOfFormattingRun(0));
|
||||
assertEquals("12", rt.getCTRst().getRArray(0).getT());
|
||||
|
||||
assertEquals(2, rt.getIndexOfFormattingRun(1));
|
||||
assertEquals(3, rt.getLengthOfFormattingRun(1));
|
||||
assertEquals("345", rt.getCTRst().getRArray(1).getT());
|
||||
|
||||
assertEquals(5, rt.getIndexOfFormattingRun(2));
|
||||
assertEquals(3, rt.getLengthOfFormattingRun(2));
|
||||
assertEquals(2, rt.getLengthOfFormattingRun(2));
|
||||
assertEquals("67", rt.getCTRst().getRArray(2).getT());
|
||||
|
||||
assertEquals(8, rt.getIndexOfFormattingRun(3));
|
||||
assertEquals(1, rt.getLengthOfFormattingRun(3));
|
||||
assertEquals(7, rt.getIndexOfFormattingRun(3));
|
||||
assertEquals(2, rt.getLengthOfFormattingRun(3));
|
||||
assertEquals("89", rt.getCTRst().getRArray(3).getT());
|
||||
}
|
||||
|
||||
public void testClearFormatting() {
|
||||
@ -142,4 +149,145 @@ public final class TestXSSFRichTextString extends TestCase {
|
||||
assertEquals("abc\r2ef\r", rt.getString());
|
||||
|
||||
}
|
||||
|
||||
public void testApplyFont_lowlevel(){
|
||||
CTRst st = CTRst.Factory.newInstance();
|
||||
String text = "Apache Software Foundation";
|
||||
XSSFRichTextString str = new XSSFRichTextString(text);
|
||||
assertEquals(26, text.length());
|
||||
|
||||
st.addNewR().setT(text);
|
||||
|
||||
TreeMap<Integer, CTRPrElt> formats = str.getFormatMap(st);
|
||||
assertEquals(1, formats.size());
|
||||
assertEquals(26, (int)formats.firstEntry().getKey());
|
||||
assertNull(formats.firstEntry().getValue());
|
||||
|
||||
CTRPrElt fmt1 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 0, 6, fmt1);
|
||||
assertEquals(2, formats.size());
|
||||
assertEquals("[6, 26]", formats.keySet().toString());
|
||||
Object[] runs1 = formats.values().toArray();
|
||||
assertSame(fmt1, runs1[0]);
|
||||
assertSame(null, runs1[1]);
|
||||
|
||||
CTRPrElt fmt2 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 7, 15, fmt2);
|
||||
assertEquals(4, formats.size());
|
||||
assertEquals("[6, 7, 15, 26]", formats.keySet().toString());
|
||||
Object[] runs2 = formats.values().toArray();
|
||||
assertSame(fmt1, runs2[0]);
|
||||
assertSame(null, runs2[1]);
|
||||
assertSame(fmt2, runs2[2]);
|
||||
assertSame(null, runs2[3]);
|
||||
|
||||
CTRPrElt fmt3 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 6, 7, fmt3);
|
||||
assertEquals(4, formats.size());
|
||||
assertEquals("[6, 7, 15, 26]", formats.keySet().toString());
|
||||
Object[] runs3 = formats.values().toArray();
|
||||
assertSame(fmt1, runs3[0]);
|
||||
assertSame(fmt3, runs3[1]);
|
||||
assertSame(fmt2, runs3[2]);
|
||||
assertSame(null, runs3[3]);
|
||||
|
||||
CTRPrElt fmt4 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 0, 7, fmt4);
|
||||
assertEquals(3, formats.size());
|
||||
assertEquals("[7, 15, 26]", formats.keySet().toString());
|
||||
Object[] runs4 = formats.values().toArray();
|
||||
assertSame(fmt4, runs4[0]);
|
||||
assertSame(fmt2, runs4[1]);
|
||||
assertSame(null, runs4[2]);
|
||||
|
||||
CTRPrElt fmt5 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 0, 26, fmt5);
|
||||
assertEquals(1, formats.size());
|
||||
assertEquals("[26]", formats.keySet().toString());
|
||||
Object[] runs5 = formats.values().toArray();
|
||||
assertSame(fmt5, runs5[0]);
|
||||
|
||||
CTRPrElt fmt6 = CTRPrElt.Factory.newInstance();
|
||||
str.applyFont(formats, 15, 26, fmt6);
|
||||
assertEquals(2, formats.size());
|
||||
assertEquals("[15, 26]", formats.keySet().toString());
|
||||
Object[] runs6 = formats.values().toArray();
|
||||
assertSame(fmt5, runs6[0]);
|
||||
assertSame(fmt6, runs6[1]);
|
||||
|
||||
str.applyFont(formats, 0, 26, null);
|
||||
assertEquals(1, formats.size());
|
||||
assertEquals("[26]", formats.keySet().toString());
|
||||
Object[] runs7 = formats.values().toArray();
|
||||
assertSame(null, runs7[0]);
|
||||
|
||||
str.applyFont(formats, 15, 26, fmt6);
|
||||
assertEquals(2, formats.size());
|
||||
assertEquals("[15, 26]", formats.keySet().toString());
|
||||
Object[] runs8 = formats.values().toArray();
|
||||
assertSame(null, runs8[0]);
|
||||
assertSame(fmt6, runs8[1]);
|
||||
|
||||
str.applyFont(formats, 15, 26, fmt5);
|
||||
assertEquals(2, formats.size());
|
||||
assertEquals("[15, 26]", formats.keySet().toString());
|
||||
Object[] runs9 = formats.values().toArray();
|
||||
assertSame(null, runs9[0]);
|
||||
assertSame(fmt5, runs9[1]);
|
||||
|
||||
str.applyFont(formats, 2, 20, fmt6);
|
||||
assertEquals(3, formats.size());
|
||||
assertEquals("[2, 20, 26]", formats.keySet().toString());
|
||||
Object[] runs10 = formats.values().toArray();
|
||||
assertSame(null, runs10[0]);
|
||||
assertSame(fmt6, runs10[1]);
|
||||
assertSame(fmt5, runs10[2]);
|
||||
|
||||
str.applyFont(formats, 22, 24, fmt4);
|
||||
assertEquals(5, formats.size());
|
||||
assertEquals("[2, 20, 22, 24, 26]", formats.keySet().toString());
|
||||
Object[] runs11 = formats.values().toArray();
|
||||
assertSame(null, runs11[0]);
|
||||
assertSame(fmt6, runs11[1]);
|
||||
assertSame(fmt5, runs11[2]);
|
||||
assertSame(fmt4, runs11[3]);
|
||||
assertSame(fmt5, runs11[4]);
|
||||
|
||||
str.applyFont(formats, 0, 10, fmt1);
|
||||
assertEquals(5, formats.size());
|
||||
assertEquals("[10, 20, 22, 24, 26]", formats.keySet().toString());
|
||||
Object[] runs12 = formats.values().toArray();
|
||||
assertSame(fmt1, runs12[0]);
|
||||
assertSame(fmt6, runs12[1]);
|
||||
assertSame(fmt5, runs12[2]);
|
||||
assertSame(fmt4, runs12[3]);
|
||||
assertSame(fmt5, runs12[4]);
|
||||
}
|
||||
|
||||
public void testApplyFont_usermodel(){
|
||||
String text = "Apache Software Foundation";
|
||||
XSSFRichTextString str = new XSSFRichTextString(text);
|
||||
XSSFFont font1 = new XSSFFont();
|
||||
XSSFFont font2 = new XSSFFont();
|
||||
XSSFFont font3 = new XSSFFont();
|
||||
str.applyFont(font1);
|
||||
assertEquals(1, str.numFormattingRuns());
|
||||
|
||||
str.applyFont(0, 6, font1);
|
||||
str.applyFont(6, text.length(), font2);
|
||||
assertEquals(2, str.numFormattingRuns());
|
||||
assertEquals("Apache", str.getCTRst().getRArray(0).getT());
|
||||
assertEquals(" Software Foundation", str.getCTRst().getRArray(1).getT());
|
||||
|
||||
str.applyFont(15, 26, font3);
|
||||
assertEquals(3, str.numFormattingRuns());
|
||||
assertEquals("Apache", str.getCTRst().getRArray(0).getT());
|
||||
assertEquals(" Software", str.getCTRst().getRArray(1).getT());
|
||||
assertEquals(" Foundation", str.getCTRst().getRArray(2).getT());
|
||||
|
||||
str.applyFont(6, text.length(), font2);
|
||||
assertEquals(2, str.numFormattingRuns());
|
||||
assertEquals("Apache", str.getCTRst().getRArray(0).getT());
|
||||
assertEquals(" Software Foundation", str.getCTRst().getRArray(1).getT());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user