60337: XWPFTableRow.isRepeatHeader throws NullPointerException, setRepeatHeader does not overwrite old value

Task-Url: https://bz.apache.org/bugzilla/show_bug.cgi?id=60337


git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1768153 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Mark Murphy 2016-11-05 06:12:24 +00:00
parent abe0740d3a
commit 70724609b1
5 changed files with 187 additions and 53 deletions

View File

@ -0,0 +1,33 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.xwpf.model;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
public final class WMLHelper {
public static boolean STOnOffToBoolean (STOnOff.Enum value) {
if (value == STOnOff.TRUE || value == STOnOff.ON || value == STOnOff.X_1) {
return true;
}
return false;
}
public static STOnOff.Enum BooleanToSTOnOff (boolean value) {
return (value ? STOnOff.TRUE : STOnOff.FALSE);
}
}

View File

@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.apache.poi.util.Internal; import org.apache.poi.util.Internal;
import org.apache.poi.xwpf.model.WMLHelper;
import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHeight;
@ -192,55 +193,74 @@ public class XWPFTableRow {
*/ */
public boolean isCantSplitRow() { public boolean isCantSplitRow() {
boolean isCant = false; boolean isCant = false;
if (ctRow.isSetTrPr()) {
CTTrPr trpr = getTrPr(); CTTrPr trpr = getTrPr();
if (trpr.sizeOfCantSplitArray() > 0) { if (trpr.sizeOfCantSplitArray() > 0) {
CTOnOff onoff = trpr.getCantSplitArray(0); CTOnOff onoff = trpr.getCantSplitArray(0);
isCant = onoff.getVal().equals(STOnOff.ON); isCant = (onoff.isSetVal() ? WMLHelper.STOnOffToBoolean(onoff.getVal()) : true);
}
} }
return isCant; return isCant;
} }
/** /**
* This attribute controls whether to allow table rows to split across pages. * Controls whether to allow this table row to split across pages.
* The logic for this attribute is a little unusual: a true value means * The logic for this attribute is a little unusual: a true value means
* DON'T allow rows to split, false means allow rows to split. * DON'T allow rows to split, false means allow rows to split.
* *
* @param split - if true, don't allow rows to be split. If false, allow * @param split - if true, don't allow row to be split. If false, allow
* rows to be split. * row to be split.
*/ */
public void setCantSplitRow(boolean split) { public void setCantSplitRow(boolean split) {
CTTrPr trpr = getTrPr(); CTTrPr trpr = getTrPr();
CTOnOff onoff = trpr.addNewCantSplit(); CTOnOff onoff = (trpr.sizeOfCantSplitArray() > 0 ? trpr.getCantSplitArray(0) : trpr.addNewCantSplit());
onoff.setVal(split ? STOnOff.ON : STOnOff.OFF); onoff.setVal(WMLHelper.BooleanToSTOnOff(split));
} }
/** /**
* Return true if a table's header row should be repeated at the top of a * Return true if a table's header row should be repeated at the top of a
* table split across pages. * table split across pages. NOTE - Word will not repeat a table row unless
* all preceding rows of the table are also repeated. This function returns
* false if the row will not be repeated even if the repeat tag is present
* for this row.
* *
* @return true if table's header row should be repeated at the top of each * @return true if table's header row should be repeated at the top of each
* page of table, false otherwise. * page of table, false otherwise.
*/ */
public boolean isRepeatHeader() { public boolean isRepeatHeader() {
boolean repeat = false; boolean repeat = false;
for (XWPFTableRow row : table.getRows()) {
repeat = row.getRepeat();
if (row == this || !repeat) {
break;
}
}
return repeat;
}
private boolean getRepeat() {
boolean repeat = false;
if (ctRow.isSetTrPr()) {
CTTrPr trpr = getTrPr(); CTTrPr trpr = getTrPr();
if (trpr.sizeOfTblHeaderArray() > 0) { if (trpr.sizeOfTblHeaderArray() > 0) {
CTOnOff rpt = trpr.getTblHeaderArray(0); CTOnOff rpt = trpr.getTblHeaderArray(0);
repeat = rpt.getVal().equals(STOnOff.ON); repeat = (rpt.isSetVal() ? WMLHelper.STOnOffToBoolean(rpt.getVal()) : true);
}
} }
return repeat; return repeat;
} }
/** /**
* This attribute controls whether to repeat a table's header row at the top * This attribute controls whether to repeat a table's header row at the top
* of a table split across pages. * of a table split across pages. NOTE - for a row to be repeated, all preceding
* rows in the table must also be repeated.
* *
* @param repeat - if TRUE, repeat header row at the top of each page of table; * @param repeat - if TRUE, repeat header row at the top of each page of table;
* if FALSE, don't repeat header row. * if FALSE, don't repeat header row.
*/ */
public void setRepeatHeader(boolean repeat) { public void setRepeatHeader(boolean repeat) {
CTTrPr trpr = getTrPr(); CTTrPr trpr = getTrPr();
CTOnOff onoff = trpr.addNewTblHeader(); CTOnOff onoff = (trpr.sizeOfTblHeaderArray() > 0 ? trpr.getTblHeaderArray(0) : trpr.addNewTblHeader());
onoff.setVal(repeat ? STOnOff.ON : STOnOff.OFF); onoff.setVal(WMLHelper.BooleanToSTOnOff(repeat));
} }
} }

View File

@ -17,21 +17,26 @@
package org.apache.poi.xwpf.usermodel; package org.apache.poi.xwpf.usermodel;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase;
import org.apache.poi.xwpf.XWPFTestDataSamples; import org.apache.poi.xwpf.XWPFTestDataSamples;
import org.junit.Ignore;
import org.junit.Test;
public final class TestXWPFSDT extends TestCase { public final class TestXWPFSDT {
/** /**
* Test simple tag and title extraction from SDT * Test simple tag and title extraction from SDT
* *
* @throws Exception * @throws Exception
*/ */
@Test
public void testTagTitle() throws Exception { public void testTagTitle() throws Exception {
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug54849.docx"); XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug54849.docx");
String tag = null; String tag = null;
@ -51,7 +56,7 @@ public final class TestXWPFSDT extends TestCase {
assertEquals("title", "MyTitle", title); assertEquals("title", "MyTitle", title);
} }
@Test
public void testGetSDTs() throws Exception { public void testGetSDTs() throws Exception {
String[] contents = new String[]{ String[] contents = new String[]{
"header_rich_text", "header_rich_text",
@ -83,6 +88,7 @@ public final class TestXWPFSDT extends TestCase {
/** /**
* POI-54771 and TIKA-1317 * POI-54771 and TIKA-1317
*/ */
@Test
public void testSDTAsCell() throws Exception { public void testSDTAsCell() throws Exception {
//Bug54771a.docx and Bug54771b.docx test slightly //Bug54771a.docx and Bug54771b.docx test slightly
//different recursion patterns. Keep both! //different recursion patterns. Keep both!
@ -110,6 +116,7 @@ public final class TestXWPFSDT extends TestCase {
/** /**
* POI-55142 and Tika 1130 * POI-55142 and Tika 1130
*/ */
@Test
public void testNewLinesBetweenRuns() throws Exception { public void testNewLinesBetweenRuns() throws Exception {
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug55142.docx"); XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug55142.docx");
List<AbstractXWPFSDT> sdts = extractAllSDTs(doc); List<AbstractXWPFSDT> sdts = extractAllSDTs(doc);
@ -132,6 +139,7 @@ public final class TestXWPFSDT extends TestCase {
} }
} }
@Ignore
public void test60341() throws IOException { public void test60341() throws IOException {
//handle sdtbody without an sdtpr //handle sdtbody without an sdtpr
XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug60341.docx"); XWPFDocument doc = XWPFTestDataSamples.openSampleDocument("Bug60341.docx");

View File

@ -17,51 +17,124 @@
package org.apache.poi.xwpf.usermodel; package org.apache.poi.xwpf.usermodel;
import junit.framework.TestCase; import static org.junit.Assert.assertFalse;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow; import static org.junit.Assert.assertNotNull;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl; import static org.junit.Assert.assertTrue;
public class TestXWPFTableRow extends TestCase { import java.io.IOException;
@Override
protected void setUp() throws Exception { import org.apache.poi.xwpf.XWPFTestDataSamples;
super.setUp(); import org.junit.Test;
public class TestXWPFTableRow {
@Test
public void testCreateRow() throws IOException {
XWPFDocument doc = new XWPFDocument();
XWPFTable table = doc.createTable(1, 1);
XWPFTableRow tr = table.createRow();
assertNotNull(tr);
doc.close();
} }
public void testCreateRow() throws Exception { @Test
CTRow ctRow = CTRow.Factory.newInstance(); public void testSetGetCantSplitRow() throws IOException {
assertNotNull(ctRow);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
public void testSetGetCantSplitRow() {
// create a table // create a table
XWPFDocument doc = new XWPFDocument(); XWPFDocument doc = new XWPFDocument();
CTTbl ctTable = CTTbl.Factory.newInstance(); XWPFTable table = doc.createTable(1, 1);
XWPFTable table = new XWPFTable(ctTable, doc);
// table has a single row by default; grab it // table has a single row by default; grab it
XWPFTableRow tr = table.getRow(0); XWPFTableRow tr = table.getRow(0);
assertNotNull(tr); assertNotNull(tr);
// Assert the repeat header is false by default
boolean isCantSplit = tr.isCantSplitRow();
assertFalse(isCantSplit);
// Repeat the header
tr.setCantSplitRow(true); tr.setCantSplitRow(true);
boolean isCant = tr.isCantSplitRow(); isCantSplit = tr.isCantSplitRow();
assert (isCant); assertTrue(isCantSplit);
// Make the header no longer repeating
tr.setCantSplitRow(false);
isCantSplit = tr.isCantSplitRow();
assertFalse(isCantSplit);
doc.close();
} }
public void testSetGetRepeatHeader() { @Test
public void testSetGetRepeatHeader() throws IOException {
// create a table // create a table
XWPFDocument doc = new XWPFDocument(); XWPFDocument doc = new XWPFDocument();
CTTbl ctTable = CTTbl.Factory.newInstance(); XWPFTable table = doc.createTable(3, 1);
XWPFTable table = new XWPFTable(ctTable, doc);
// table has a single row by default; grab it // table has a single row by default; grab it
XWPFTableRow tr = table.getRow(0); XWPFTableRow tr = table.getRow(0);
assertNotNull(tr); assertNotNull(tr);
tr.setRepeatHeader(true); // Assert the repeat header is false by default
boolean isRpt = tr.isRepeatHeader(); boolean isRpt = tr.isRepeatHeader();
assert (isRpt); assertFalse(isRpt);
// Repeat the header
tr.setRepeatHeader(true);
isRpt = tr.isRepeatHeader();
assertTrue(isRpt);
// Make the header no longer repeating
tr.setRepeatHeader(false);
isRpt = tr.isRepeatHeader();
assertFalse(isRpt);
// If the third row is set to repeat, but not the second,
// isRepeatHeader should report false because Word will
// ignore it.
tr = table.getRow(2);
tr.setRepeatHeader(true);
isRpt = tr.isRepeatHeader();
assertFalse(isRpt);
doc.close();
}
// Test that validates the table header value can be parsed from a document
// generated in Word
@Test
public void testIsRepeatHeader() throws Exception {
XWPFDocument doc = XWPFTestDataSamples
.openSampleDocument("Bug60337.docx");
XWPFTable table = doc.getTables().get(0);
XWPFTableRow tr = table.getRow(0);
boolean isRpt = tr.isRepeatHeader();
assertTrue(isRpt);
tr = table.getRow(1);
isRpt = tr.isRepeatHeader();
assertFalse(isRpt);
tr = table.getRow(2);
isRpt = tr.isRepeatHeader();
assertFalse(isRpt);
}
// Test that validates the table header value can be parsed from a document
// generated in Word
@Test
public void testIsCantSplit() throws Exception {
XWPFDocument doc = XWPFTestDataSamples
.openSampleDocument("Bug60337.docx");
XWPFTable table = doc.getTables().get(0);
XWPFTableRow tr = table.getRow(0);
boolean isCantSplit = tr.isCantSplitRow();
assertFalse(isCantSplit);
tr = table.getRow(1);
isCantSplit = tr.isCantSplitRow();
assertFalse(isCantSplit);
tr = table.getRow(2);
isCantSplit = tr.isCantSplitRow();
assertTrue(isCantSplit);
} }
} }

Binary file not shown.