Bugzilla 47363 - Fixed HSSFSheet to allow addition of data validations after sheet protection
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@784240 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
f14b64759d
commit
635c570598
@ -35,6 +35,7 @@
|
|||||||
<release version="3.5-beta7" date="2009-??-??">
|
<release version="3.5-beta7" date="2009-??-??">
|
||||||
</release>
|
</release>
|
||||||
<release version="3.5-beta6" date="2009-06-22">
|
<release version="3.5-beta6" date="2009-06-22">
|
||||||
|
<action dev="POI-DEVELOPERS" type="fix">47363 - Fixed HSSFSheet to allow addition of data validations after sheet protection</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">47294 - Fixed XSSFWorkbook#setRepeatingRowsAndColumns to tolerate sheet names with quotes</action>
|
<action dev="POI-DEVELOPERS" type="fix">47294 - Fixed XSSFWorkbook#setRepeatingRowsAndColumns to tolerate sheet names with quotes</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">47309 - Fixed logic in HSSFCell.getCellComment to handle sheets with more than 65536 comments</action>
|
<action dev="POI-DEVELOPERS" type="fix">47309 - Fixed logic in HSSFCell.getCellComment to handle sheets with more than 65536 comments</action>
|
||||||
<action dev="POI-DEVELOPERS" type="fix">46776 - Added clone() method to MulBlankRecord to fix crash in Sheet.cloneSheet()</action>
|
<action dev="POI-DEVELOPERS" type="fix">46776 - Added clone() method to MulBlankRecord to fix crash in Sheet.cloneSheet()</action>
|
||||||
|
@ -27,6 +27,7 @@ import org.apache.poi.hssf.record.CalcCountRecord;
|
|||||||
import org.apache.poi.hssf.record.CalcModeRecord;
|
import org.apache.poi.hssf.record.CalcModeRecord;
|
||||||
import org.apache.poi.hssf.record.DVALRecord;
|
import org.apache.poi.hssf.record.DVALRecord;
|
||||||
import org.apache.poi.hssf.record.DateWindow1904Record;
|
import org.apache.poi.hssf.record.DateWindow1904Record;
|
||||||
|
import org.apache.poi.hssf.record.DefaultColWidthRecord;
|
||||||
import org.apache.poi.hssf.record.DefaultRowHeightRecord;
|
import org.apache.poi.hssf.record.DefaultRowHeightRecord;
|
||||||
import org.apache.poi.hssf.record.DeltaRecord;
|
import org.apache.poi.hssf.record.DeltaRecord;
|
||||||
import org.apache.poi.hssf.record.DimensionsRecord;
|
import org.apache.poi.hssf.record.DimensionsRecord;
|
||||||
@ -62,21 +63,23 @@ import org.apache.poi.hssf.record.UncalcedRecord;
|
|||||||
import org.apache.poi.hssf.record.UnknownRecord;
|
import org.apache.poi.hssf.record.UnknownRecord;
|
||||||
import org.apache.poi.hssf.record.WindowOneRecord;
|
import org.apache.poi.hssf.record.WindowOneRecord;
|
||||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.ColumnInfoRecordsAggregate;
|
||||||
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
|
import org.apache.poi.hssf.record.aggregates.ConditionalFormattingTable;
|
||||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
||||||
import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
||||||
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
|
||||||
import org.apache.poi.hssf.record.pivottable.ViewDefinitionRecord;
|
import org.apache.poi.hssf.record.pivottable.ViewDefinitionRecord;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds correct insert positions for records in workbook streams<p/>
|
* Finds correct insert positions for records in workbook streams<p/>
|
||||||
*
|
*
|
||||||
* See OOO excelfileformat.pdf sec. 4.2.5 'Record Order in a BIFF8 Workbook Stream'
|
* See OOO excelfileformat.pdf sec. 4.2.5 'Record Order in a BIFF8 Workbook Stream'
|
||||||
*
|
*
|
||||||
* @author Josh Micich
|
* @author Josh Micich
|
||||||
*/
|
*/
|
||||||
final class RecordOrderer {
|
final class RecordOrderer {
|
||||||
|
|
||||||
// TODO - simplify logic using a generalised record ordering
|
// TODO - simplify logic using a generalised record ordering
|
||||||
|
|
||||||
private RecordOrderer() {
|
private RecordOrderer() {
|
||||||
@ -84,7 +87,6 @@ final class RecordOrderer {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Adds the specified new record in the correct place in sheet records list
|
* Adds the specified new record in the correct place in sheet records list
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public static void addNewSheetRecord(List<RecordBase> sheetRecords, RecordBase newRecord) {
|
public static void addNewSheetRecord(List<RecordBase> sheetRecords, RecordBase newRecord) {
|
||||||
int index = findSheetInsertPos(sheetRecords, newRecord.getClass());
|
int index = findSheetInsertPos(sheetRecords, newRecord.getClass());
|
||||||
@ -107,9 +109,69 @@ final class RecordOrderer {
|
|||||||
if (recClass == PageSettingsBlock.class) {
|
if (recClass == PageSettingsBlock.class) {
|
||||||
return getPageBreakRecordInsertPos(records);
|
return getPageBreakRecordInsertPos(records);
|
||||||
}
|
}
|
||||||
|
if (recClass == WorksheetProtectionBlock.class) {
|
||||||
|
return getWorksheetProtectionBlockInsertPos(records);
|
||||||
|
}
|
||||||
throw new RuntimeException("Unexpected record class (" + recClass.getName() + ")");
|
throw new RuntimeException("Unexpected record class (" + recClass.getName() + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds the index where the protection block should be inserted
|
||||||
|
* @param records the records for this sheet
|
||||||
|
* <pre>
|
||||||
|
* + BOF
|
||||||
|
* o INDEX
|
||||||
|
* o Calculation Settings Block
|
||||||
|
* o PRINTHEADERS
|
||||||
|
* o PRINTGRIDLINES
|
||||||
|
* o GRIDSET
|
||||||
|
* o GUTS
|
||||||
|
* o DEFAULTROWHEIGHT
|
||||||
|
* o SHEETPR
|
||||||
|
* o Page Settings Block
|
||||||
|
* o Worksheet Protection Block
|
||||||
|
* o DEFCOLWIDTH
|
||||||
|
* oo COLINFO
|
||||||
|
* o SORT
|
||||||
|
* + DIMENSION
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
private static int getWorksheetProtectionBlockInsertPos(List<RecordBase> records) {
|
||||||
|
int i = getDimensionsIndex(records);
|
||||||
|
while (i > 0) {
|
||||||
|
i--;
|
||||||
|
Object rb = records.get(i);
|
||||||
|
if (!isProtectionSubsequentRecord(rb)) {
|
||||||
|
return i+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalStateException("did not find insert pos for protection block");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* These records may occur between the 'Worksheet Protection Block' and DIMENSION:
|
||||||
|
* <pre>
|
||||||
|
* o DEFCOLWIDTH
|
||||||
|
* oo COLINFO
|
||||||
|
* o SORT
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
private static boolean isProtectionSubsequentRecord(Object rb) {
|
||||||
|
if (rb instanceof ColumnInfoRecordsAggregate) {
|
||||||
|
return true; // oo COLINFO
|
||||||
|
}
|
||||||
|
if (rb instanceof Record) {
|
||||||
|
Record record = (Record) rb;
|
||||||
|
switch (record.getSid()) {
|
||||||
|
case DefaultColWidthRecord.sid:
|
||||||
|
case UnknownRecord.SORT_0090:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static int getPageBreakRecordInsertPos(List<RecordBase> records) {
|
private static int getPageBreakRecordInsertPos(List<RecordBase> records) {
|
||||||
int dimensionsIndex = getDimensionsIndex(records);
|
int dimensionsIndex = getDimensionsIndex(records);
|
||||||
int i = dimensionsIndex-1;
|
int i = dimensionsIndex-1;
|
||||||
@ -163,7 +225,7 @@ final class RecordOrderer {
|
|||||||
if (rb instanceof DataValidityTable) {
|
if (rb instanceof DataValidityTable) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Record rec = (Record) rb;
|
Record rec = (Record) rb;
|
||||||
switch (rec.getSid()) {
|
switch (rec.getSid()) {
|
||||||
case WindowTwoRecord.sid:
|
case WindowTwoRecord.sid:
|
||||||
@ -171,7 +233,7 @@ final class RecordOrderer {
|
|||||||
case PaneRecord.sid:
|
case PaneRecord.sid:
|
||||||
case SelectionRecord.sid:
|
case SelectionRecord.sid:
|
||||||
case UnknownRecord.STANDARDWIDTH_0099:
|
case UnknownRecord.STANDARDWIDTH_0099:
|
||||||
// MergedCellsTable usually here
|
// MergedCellsTable usually here
|
||||||
case UnknownRecord.LABELRANGES_015F:
|
case UnknownRecord.LABELRANGES_015F:
|
||||||
case UnknownRecord.PHONETICPR_00EF:
|
case UnknownRecord.PHONETICPR_00EF:
|
||||||
// ConditionalFormattingTable goes here
|
// ConditionalFormattingTable goes here
|
||||||
@ -187,13 +249,13 @@ final class RecordOrderer {
|
|||||||
for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
|
for (int i = records.size() - 2; i >= 0; i--) { // -2 to skip EOF record
|
||||||
Object rb = records.get(i);
|
Object rb = records.get(i);
|
||||||
if (!(rb instanceof Record)) {
|
if (!(rb instanceof Record)) {
|
||||||
// DataValidityTable, ConditionalFormattingTable,
|
// DataValidityTable, ConditionalFormattingTable,
|
||||||
// even PageSettingsBlock (which doesn't normally appear after 'View Settings')
|
// even PageSettingsBlock (which doesn't normally appear after 'View Settings')
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Record rec = (Record) rb;
|
Record rec = (Record) rb;
|
||||||
switch (rec.getSid()) {
|
switch (rec.getSid()) {
|
||||||
// 'View Settings' (4 records)
|
// 'View Settings' (4 records)
|
||||||
case WindowTwoRecord.sid:
|
case WindowTwoRecord.sid:
|
||||||
case SCLRecord.sid:
|
case SCLRecord.sid:
|
||||||
case PaneRecord.sid:
|
case PaneRecord.sid:
|
||||||
@ -206,11 +268,11 @@ final class RecordOrderer {
|
|||||||
throw new RuntimeException("Did not find Window2 record");
|
throw new RuntimeException("Did not find Window2 record");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the index where the sheet validations header record should be inserted
|
* Finds the index where the sheet validations header record should be inserted
|
||||||
* @param records the records for this sheet
|
* @param records the records for this sheet
|
||||||
*
|
*
|
||||||
* + WINDOW2
|
* + WINDOW2
|
||||||
* o SCL
|
* o SCL
|
||||||
* o PANE
|
* o PANE
|
||||||
@ -340,7 +402,7 @@ final class RecordOrderer {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* @return <code>true</code> if the specified record ID terminates a sequence of Row block records
|
* @return <code>true</code> if the specified record ID terminates a sequence of Row block records
|
||||||
* It is assumed that at least one row or cell value record has been found prior to the current
|
* It is assumed that at least one row or cell value record has been found prior to the current
|
||||||
* record
|
* record
|
||||||
*/
|
*/
|
||||||
public static boolean isEndOfRowBlock(int sid) {
|
public static boolean isEndOfRowBlock(int sid) {
|
||||||
@ -359,7 +421,7 @@ final class RecordOrderer {
|
|||||||
|
|
||||||
case DVALRecord.sid:
|
case DVALRecord.sid:
|
||||||
return true;
|
return true;
|
||||||
case EOFRecord.sid:
|
case EOFRecord.sid:
|
||||||
// WINDOW2 should always be present, so shouldn't have got this far
|
// WINDOW2 should always be present, so shouldn't have got this far
|
||||||
throw new RuntimeException("Found EOFRecord before WindowTwoRecord was encountered");
|
throw new RuntimeException("Found EOFRecord before WindowTwoRecord was encountered");
|
||||||
}
|
}
|
||||||
@ -367,13 +429,13 @@ final class RecordOrderer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return <code>true</code> if the specified record id normally appears in the row blocks section
|
* @return <code>true</code> if the specified record id normally appears in the row blocks section
|
||||||
* of the sheet records
|
* of the sheet records
|
||||||
*/
|
*/
|
||||||
public static boolean isRowBlockRecord(int sid) {
|
public static boolean isRowBlockRecord(int sid) {
|
||||||
switch (sid) {
|
switch (sid) {
|
||||||
case RowRecord.sid:
|
case RowRecord.sid:
|
||||||
|
|
||||||
case BlankRecord.sid:
|
case BlankRecord.sid:
|
||||||
case BoolErrRecord.sid:
|
case BoolErrRecord.sid:
|
||||||
case FormulaRecord.sid:
|
case FormulaRecord.sid:
|
||||||
|
@ -42,19 +42,15 @@ import org.apache.poi.hssf.record.IterationRecord;
|
|||||||
import org.apache.poi.hssf.record.MergeCellsRecord;
|
import org.apache.poi.hssf.record.MergeCellsRecord;
|
||||||
import org.apache.poi.hssf.record.NoteRecord;
|
import org.apache.poi.hssf.record.NoteRecord;
|
||||||
import org.apache.poi.hssf.record.ObjRecord;
|
import org.apache.poi.hssf.record.ObjRecord;
|
||||||
import org.apache.poi.hssf.record.ObjectProtectRecord;
|
|
||||||
import org.apache.poi.hssf.record.PaneRecord;
|
import org.apache.poi.hssf.record.PaneRecord;
|
||||||
import org.apache.poi.hssf.record.PasswordRecord;
|
|
||||||
import org.apache.poi.hssf.record.PrintGridlinesRecord;
|
import org.apache.poi.hssf.record.PrintGridlinesRecord;
|
||||||
import org.apache.poi.hssf.record.PrintHeadersRecord;
|
import org.apache.poi.hssf.record.PrintHeadersRecord;
|
||||||
import org.apache.poi.hssf.record.ProtectRecord;
|
|
||||||
import org.apache.poi.hssf.record.Record;
|
import org.apache.poi.hssf.record.Record;
|
||||||
import org.apache.poi.hssf.record.RecordBase;
|
import org.apache.poi.hssf.record.RecordBase;
|
||||||
import org.apache.poi.hssf.record.RefModeRecord;
|
import org.apache.poi.hssf.record.RefModeRecord;
|
||||||
import org.apache.poi.hssf.record.RowRecord;
|
import org.apache.poi.hssf.record.RowRecord;
|
||||||
import org.apache.poi.hssf.record.SCLRecord;
|
import org.apache.poi.hssf.record.SCLRecord;
|
||||||
import org.apache.poi.hssf.record.SaveRecalcRecord;
|
import org.apache.poi.hssf.record.SaveRecalcRecord;
|
||||||
import org.apache.poi.hssf.record.ScenarioProtectRecord;
|
|
||||||
import org.apache.poi.hssf.record.SelectionRecord;
|
import org.apache.poi.hssf.record.SelectionRecord;
|
||||||
import org.apache.poi.hssf.record.UncalcedRecord;
|
import org.apache.poi.hssf.record.UncalcedRecord;
|
||||||
import org.apache.poi.hssf.record.WSBoolRecord;
|
import org.apache.poi.hssf.record.WSBoolRecord;
|
||||||
@ -68,6 +64,7 @@ import org.apache.poi.hssf.record.aggregates.MergedCellsTable;
|
|||||||
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
import org.apache.poi.hssf.record.aggregates.PageSettingsBlock;
|
||||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate;
|
||||||
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
import org.apache.poi.hssf.record.aggregates.RowRecordsAggregate;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
|
||||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.PositionTrackingVisitor;
|
||||||
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
import org.apache.poi.hssf.record.aggregates.RecordAggregate.RecordVisitor;
|
||||||
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
||||||
@ -113,11 +110,11 @@ public final class Sheet implements Model {
|
|||||||
protected DefaultRowHeightRecord defaultrowheight = null;
|
protected DefaultRowHeightRecord defaultrowheight = null;
|
||||||
private PageSettingsBlock _psBlock;
|
private PageSettingsBlock _psBlock;
|
||||||
|
|
||||||
// 'Worksheet Protection Block'
|
/**
|
||||||
protected ProtectRecord protect = null;
|
* 'Worksheet Protection Block'<br/>
|
||||||
protected ObjectProtectRecord objprotect = null;
|
* Aggregate object is always present, but possibly empty.
|
||||||
protected ScenarioProtectRecord scenprotect = null;
|
*/
|
||||||
protected PasswordRecord _password = null;
|
private final WorksheetProtectionBlock _protectionBlock = new WorksheetProtectionBlock();
|
||||||
|
|
||||||
protected WindowTwoRecord windowTwo = null;
|
protected WindowTwoRecord windowTwo = null;
|
||||||
protected SelectionRecord _selection = null;
|
protected SelectionRecord _selection = null;
|
||||||
@ -227,6 +224,11 @@ public final class Sheet implements Model {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (WorksheetProtectionBlock.isComponentRecord(recSid)) {
|
||||||
|
_protectionBlock.addRecords(rs);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (recSid == MergeCellsRecord.sid) {
|
if (recSid == MergeCellsRecord.sid) {
|
||||||
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
|
// when the MergedCellsTable is found in the right place, we expect those records to be contiguous
|
||||||
_mergedCellsTable.read(rs);
|
_mergedCellsTable.read(rs);
|
||||||
@ -299,22 +301,6 @@ public final class Sheet implements Model {
|
|||||||
{
|
{
|
||||||
windowTwo = (WindowTwoRecord) rec;
|
windowTwo = (WindowTwoRecord) rec;
|
||||||
}
|
}
|
||||||
else if ( recSid == ProtectRecord.sid )
|
|
||||||
{
|
|
||||||
protect = (ProtectRecord) rec;
|
|
||||||
}
|
|
||||||
else if ( recSid == ObjectProtectRecord.sid )
|
|
||||||
{
|
|
||||||
objprotect = (ObjectProtectRecord) rec;
|
|
||||||
}
|
|
||||||
else if ( recSid == ScenarioProtectRecord.sid )
|
|
||||||
{
|
|
||||||
scenprotect = (ScenarioProtectRecord) rec;
|
|
||||||
}
|
|
||||||
else if ( recSid == PasswordRecord.sid )
|
|
||||||
{
|
|
||||||
_password = (PasswordRecord) rec;
|
|
||||||
}
|
|
||||||
else if ( recSid == GutsRecord.sid )
|
else if ( recSid == GutsRecord.sid )
|
||||||
{
|
{
|
||||||
_gutsRecord = (GutsRecord) rec;
|
_gutsRecord = (GutsRecord) rec;
|
||||||
@ -348,6 +334,7 @@ public final class Sheet implements Model {
|
|||||||
_rowsAggregate = rra;
|
_rowsAggregate = rra;
|
||||||
// put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
|
// put merged cells table in the right place (regardless of where the first MergedCellsRecord was found */
|
||||||
RecordOrderer.addNewSheetRecord(records, _mergedCellsTable);
|
RecordOrderer.addNewSheetRecord(records, _mergedCellsTable);
|
||||||
|
RecordOrderer.addNewSheetRecord(records, _protectionBlock);
|
||||||
if (log.check( POILogger.DEBUG ))
|
if (log.check( POILogger.DEBUG ))
|
||||||
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
|
log.log(POILogger.DEBUG, "sheet createSheet (existing file) exited");
|
||||||
}
|
}
|
||||||
@ -432,7 +419,7 @@ public final class Sheet implements Model {
|
|||||||
records.add(_psBlock);
|
records.add(_psBlock);
|
||||||
|
|
||||||
// 'Worksheet Protection Block' (after 'Page Settings Block' and before DEFCOLWIDTH)
|
// 'Worksheet Protection Block' (after 'Page Settings Block' and before DEFCOLWIDTH)
|
||||||
// PROTECT record normally goes here, don't add yet since the flag is initially false
|
records.add(_protectionBlock); // initially empty
|
||||||
|
|
||||||
defaultcolwidth = createDefaultColWidth();
|
defaultcolwidth = createDefaultColWidth();
|
||||||
records.add( defaultcolwidth);
|
records.add( defaultcolwidth);
|
||||||
@ -1407,62 +1394,11 @@ public final class Sheet implements Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* creates an ObjectProtect record with protect set to false.
|
* @return the {@link WorksheetProtectionBlock} for this sheet
|
||||||
*/
|
*/
|
||||||
private static ObjectProtectRecord createObjectProtect() {
|
public WorksheetProtectionBlock getProtectionBlock() {
|
||||||
if (log.check( POILogger.DEBUG ))
|
return _protectionBlock;
|
||||||
log.log(POILogger.DEBUG, "create protect record with protection disabled");
|
|
||||||
ObjectProtectRecord retval = new ObjectProtectRecord();
|
|
||||||
|
|
||||||
retval.setProtect(false);
|
|
||||||
return retval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a ScenarioProtect record with protect set to false.
|
|
||||||
*/
|
|
||||||
private static ScenarioProtectRecord createScenarioProtect() {
|
|
||||||
if (log.check( POILogger.DEBUG ))
|
|
||||||
log.log(POILogger.DEBUG, "create protect record with protection disabled");
|
|
||||||
ScenarioProtectRecord retval = new ScenarioProtectRecord();
|
|
||||||
|
|
||||||
retval.setProtect(false);
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the ProtectRecord. If one is not contained in the sheet, then one is created.
|
|
||||||
*/
|
|
||||||
public ProtectRecord getProtect() {
|
|
||||||
if (protect == null) {
|
|
||||||
protect = new ProtectRecord(false);
|
|
||||||
// Insert the newly created protect record just before DefaultColWidthRecord
|
|
||||||
int loc = findFirstRecordLocBySid(DefaultColWidthRecord.sid);
|
|
||||||
_records.add(loc, protect);
|
|
||||||
}
|
|
||||||
return protect;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the PasswordRecord. If one is not contained in the sheet, then one is created.
|
|
||||||
*/
|
|
||||||
public PasswordRecord getPassword() {
|
|
||||||
if (_password == null) {
|
|
||||||
_password = createPassword();
|
|
||||||
//Insert the newly created password record at the end of the record (just before the EOF)
|
|
||||||
int loc = findFirstRecordLocBySid(EOFRecord.sid);
|
|
||||||
_records.add(loc, _password);
|
|
||||||
}
|
|
||||||
return _password;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* creates a Password record with password set to 0x0000.
|
|
||||||
*/
|
|
||||||
private static PasswordRecord createPassword() {
|
|
||||||
return new PasswordRecord(0x0000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets whether the gridlines are shown in a viewer.
|
* Sets whether the gridlines are shown in a viewer.
|
||||||
* @param show whether to show gridlines or not
|
* @param show whether to show gridlines or not
|
||||||
@ -1601,68 +1537,6 @@ public final class Sheet implements Model {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* protect a spreadsheet with a password (not encypted, just sets protect
|
|
||||||
* flags and the password.
|
|
||||||
* @param password to set
|
|
||||||
* @param objects are protected
|
|
||||||
* @param scenarios are protected
|
|
||||||
*/
|
|
||||||
public void protectSheet( String password, boolean objects, boolean scenarios ) {
|
|
||||||
int protIdx = -1;
|
|
||||||
ProtectRecord prec = getProtect();
|
|
||||||
PasswordRecord pass = getPassword();
|
|
||||||
prec.setProtect(true);
|
|
||||||
pass.setPassword(PasswordRecord.hashPassword(password));
|
|
||||||
if((objprotect == null && objects) || (scenprotect != null && scenarios)) {
|
|
||||||
protIdx = _records.indexOf( protect );
|
|
||||||
}
|
|
||||||
if(objprotect == null && objects) {
|
|
||||||
ObjectProtectRecord rec = createObjectProtect();
|
|
||||||
rec.setProtect(true);
|
|
||||||
_records.add(protIdx+1,rec);
|
|
||||||
objprotect = rec;
|
|
||||||
}
|
|
||||||
if(scenprotect == null && scenarios) {
|
|
||||||
ScenarioProtectRecord srec = createScenarioProtect();
|
|
||||||
srec.setProtect(true);
|
|
||||||
_records.add(protIdx+2,srec);
|
|
||||||
scenprotect = srec;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* unprotect objects in the sheet (will not protect them, but any set to false are
|
|
||||||
* unprotected.
|
|
||||||
* @param sheet is unprotected (false = unprotect)
|
|
||||||
* @param objects are unprotected (false = unprotect)
|
|
||||||
* @param scenarios are unprotected (false = unprotect)
|
|
||||||
*/
|
|
||||||
public void unprotectSheet( boolean sheet, boolean objects, boolean scenarios ) {
|
|
||||||
|
|
||||||
if (!sheet) {
|
|
||||||
ProtectRecord prec = getProtect();
|
|
||||||
prec.setProtect(sheet);
|
|
||||||
PasswordRecord pass = getPassword();
|
|
||||||
pass.setPassword((short)00);
|
|
||||||
}
|
|
||||||
if(objprotect != null && !objects) {
|
|
||||||
objprotect.setProtect(false);
|
|
||||||
}
|
|
||||||
if(scenprotect != null && !scenarios) {
|
|
||||||
scenprotect.setProtect(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return {sheet is protected, objects are proteced, scenarios are protected}
|
|
||||||
*/
|
|
||||||
public boolean[] isProtected() {
|
|
||||||
return new boolean[] { (protect != null && protect.getProtect()),
|
|
||||||
(objprotect != null && objprotect.getProtect()),
|
|
||||||
(scenprotect != null && scenprotect.getProtect())};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public void groupRowRange(int fromRow, int toRow, boolean indent)
|
public void groupRowRange(int fromRow, int toRow, boolean indent)
|
||||||
{
|
{
|
||||||
|
@ -44,6 +44,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
public static final int PRINTSIZE_0033 = 0x0033;
|
public static final int PRINTSIZE_0033 = 0x0033;
|
||||||
public static final int PLS_004D = 0x004D;
|
public static final int PLS_004D = 0x004D;
|
||||||
public static final int SHEETPR_0081 = 0x0081;
|
public static final int SHEETPR_0081 = 0x0081;
|
||||||
|
public static final int SORT_0090 = 0x0090;
|
||||||
public static final int STANDARDWIDTH_0099 = 0x0099;
|
public static final int STANDARDWIDTH_0099 = 0x0099;
|
||||||
public static final int SCL_00A0 = 0x00A0;
|
public static final int SCL_00A0 = 0x00A0;
|
||||||
public static final int BITMAP_00E9 = 0x00E9;
|
public static final int BITMAP_00E9 = 0x00E9;
|
||||||
@ -56,7 +57,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
public static final int SHEETPROTECTION_0867 = 0x0867;
|
public static final int SHEETPROTECTION_0867 = 0x0867;
|
||||||
public static final int RANGEPROTECTION_0868 = 0x0868;
|
public static final int RANGEPROTECTION_0868 = 0x0868;
|
||||||
public static final int HEADER_FOOTER_089C = 0x089C;
|
public static final int HEADER_FOOTER_089C = 0x089C;
|
||||||
|
|
||||||
private int _sid;
|
private int _sid;
|
||||||
private byte[] _rawData;
|
private byte[] _rawData;
|
||||||
|
|
||||||
@ -65,8 +66,8 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
* @param data the data
|
* @param data the data
|
||||||
*/
|
*/
|
||||||
public UnknownRecord(int id, byte[] data) {
|
public UnknownRecord(int id, byte[] data) {
|
||||||
_sid = id & 0xFFFF;
|
_sid = id & 0xFFFF;
|
||||||
_rawData = data;
|
_rawData = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -122,12 +123,12 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* These BIFF record types are known but still uninterpreted by POI
|
* These BIFF record types are known but still uninterpreted by POI
|
||||||
*
|
*
|
||||||
* @return the documented name of this BIFF record type, <code>null</code> if unknown to POI
|
* @return the documented name of this BIFF record type, <code>null</code> if unknown to POI
|
||||||
*/
|
*/
|
||||||
public static String getBiffName(int sid) {
|
public static String getBiffName(int sid) {
|
||||||
// Note to POI developers:
|
// Note to POI developers:
|
||||||
// Make sure you delete the corresponding entry from
|
// Make sure you delete the corresponding entry from
|
||||||
// this method any time a new Record subclass is created.
|
// this method any time a new Record subclass is created.
|
||||||
switch (sid) {
|
switch (sid) {
|
||||||
case PRINTSIZE_0033: return "PRINTSIZE";
|
case PRINTSIZE_0033: return "PRINTSIZE";
|
||||||
@ -135,7 +136,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
case 0x0050: return "DCON"; // Data Consolidation Information
|
case 0x0050: return "DCON"; // Data Consolidation Information
|
||||||
case 0x007F: return "IMDATA";
|
case 0x007F: return "IMDATA";
|
||||||
case SHEETPR_0081: return "SHEETPR";
|
case SHEETPR_0081: return "SHEETPR";
|
||||||
case 0x0090: return "SORT"; // Sorting Options
|
case SORT_0090: return "SORT"; // Sorting Options
|
||||||
case 0x0094: return "LHRECORD"; // .WK? File Conversion Information
|
case 0x0094: return "LHRECORD"; // .WK? File Conversion Information
|
||||||
case STANDARDWIDTH_0099: return "STANDARDWIDTH"; //Standard Column Width
|
case STANDARDWIDTH_0099: return "STANDARDWIDTH"; //Standard Column Width
|
||||||
case 0x009D: return "AUTOFILTERINFO"; // Drop-Down Arrow Count
|
case 0x009D: return "AUTOFILTERINFO"; // Drop-Down Arrow Count
|
||||||
@ -145,7 +146,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
case 0x00B2: return "SXVI"; // (pivot table) View Item
|
case 0x00B2: return "SXVI"; // (pivot table) View Item
|
||||||
case 0x00B4: return "SXIVD"; // (pivot table) Row/Column Field IDs
|
case 0x00B4: return "SXIVD"; // (pivot table) Row/Column Field IDs
|
||||||
case 0x00B5: return "SXLI"; // (pivot table) Line Item Array
|
case 0x00B5: return "SXLI"; // (pivot table) Line Item Array
|
||||||
|
|
||||||
case 0x00D3: return "OBPROJ";
|
case 0x00D3: return "OBPROJ";
|
||||||
case 0x00DC: return "PARAMQRY";
|
case 0x00DC: return "PARAMQRY";
|
||||||
case 0x00DE: return "OLESIZE";
|
case 0x00DE: return "OLESIZE";
|
||||||
@ -181,7 +182,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
case 0x087B: return "CFEX";
|
case 0x087B: return "CFEX";
|
||||||
case 0x087C: return "XFCRC";
|
case 0x087C: return "XFCRC";
|
||||||
case 0x087D: return "XFEXT";
|
case 0x087D: return "XFEXT";
|
||||||
case 0x087F: return "CONTINUEFRT12";
|
case 0x087F: return "CONTINUEFRT12";
|
||||||
case 0x088B: return "PLV";
|
case 0x088B: return "PLV";
|
||||||
case 0x088C: return "COMPAT12";
|
case 0x088C: return "COMPAT12";
|
||||||
case 0x088D: return "DXF";
|
case 0x088D: return "DXF";
|
||||||
@ -209,12 +210,11 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
|
||||||
* @return <code>true</code> if the unknown record id has been observed in POI unit tests
|
* @return <code>true</code> if the unknown record id has been observed in POI unit tests
|
||||||
*/
|
*/
|
||||||
private static boolean isObservedButUnknown(int sid) {
|
private static boolean isObservedButUnknown(int sid) {
|
||||||
switch (sid) {
|
switch (sid) {
|
||||||
case 0x0033:
|
case 0x0033:
|
||||||
// contains 2 bytes of data: 0x0001 or 0x0003
|
// contains 2 bytes of data: 0x0001 or 0x0003
|
||||||
case 0x0034:
|
case 0x0034:
|
||||||
// Seems to be written by MSAccess
|
// Seems to be written by MSAccess
|
||||||
@ -222,7 +222,7 @@ public final class UnknownRecord extends StandardRecord {
|
|||||||
// appears after last cell value record and before WINDOW2
|
// appears after last cell value record and before WINDOW2
|
||||||
case 0x01BD:
|
case 0x01BD:
|
||||||
case 0x01C2:
|
case 0x01C2:
|
||||||
// Written by Excel 2007
|
// Written by Excel 2007
|
||||||
// rawData is multiple of 12 bytes long
|
// rawData is multiple of 12 bytes long
|
||||||
// appears after last cell value record and before WINDOW2 or drawing records
|
// appears after last cell value record and before WINDOW2 or drawing records
|
||||||
case 0x089D:
|
case 0x089D:
|
||||||
|
@ -0,0 +1,245 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
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.hssf.record.aggregates;
|
||||||
|
|
||||||
|
import org.apache.poi.hssf.model.RecordStream;
|
||||||
|
import org.apache.poi.hssf.record.ObjectProtectRecord;
|
||||||
|
import org.apache.poi.hssf.record.PasswordRecord;
|
||||||
|
import org.apache.poi.hssf.record.ProtectRecord;
|
||||||
|
import org.apache.poi.hssf.record.Record;
|
||||||
|
import org.apache.poi.hssf.record.RecordFormatException;
|
||||||
|
import org.apache.poi.hssf.record.ScenarioProtectRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Groups the sheet protection records for a worksheet.
|
||||||
|
* <p/>
|
||||||
|
*
|
||||||
|
* See OOO excelfileformat.pdf sec 4.18.2 'Sheet Protection in a Workbook
|
||||||
|
* (BIFF5-BIFF8)'
|
||||||
|
*
|
||||||
|
* @author Josh Micich
|
||||||
|
*/
|
||||||
|
public final class WorksheetProtectionBlock extends RecordAggregate {
|
||||||
|
// Every one of these component records is optional
|
||||||
|
// (The whole WorksheetProtectionBlock may not be present)
|
||||||
|
private ProtectRecord _protectRecord;
|
||||||
|
private ObjectProtectRecord _objectProtectRecord;
|
||||||
|
private ScenarioProtectRecord _scenarioProtectRecord;
|
||||||
|
private PasswordRecord _passwordRecord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an empty WorksheetProtectionBlock
|
||||||
|
*/
|
||||||
|
public WorksheetProtectionBlock() {
|
||||||
|
// all fields empty
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return <code>true</code> if the specified Record sid is one belonging to
|
||||||
|
* the 'Page Settings Block'.
|
||||||
|
*/
|
||||||
|
public static boolean isComponentRecord(int sid) {
|
||||||
|
switch (sid) {
|
||||||
|
case ProtectRecord.sid:
|
||||||
|
case ObjectProtectRecord.sid:
|
||||||
|
case ScenarioProtectRecord.sid:
|
||||||
|
case PasswordRecord.sid:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean readARecord(RecordStream rs) {
|
||||||
|
switch (rs.peekNextSid()) {
|
||||||
|
case ProtectRecord.sid:
|
||||||
|
checkNotPresent(_protectRecord);
|
||||||
|
_protectRecord = (ProtectRecord) rs.getNext();
|
||||||
|
break;
|
||||||
|
case ObjectProtectRecord.sid:
|
||||||
|
checkNotPresent(_objectProtectRecord);
|
||||||
|
_objectProtectRecord = (ObjectProtectRecord) rs.getNext();
|
||||||
|
break;
|
||||||
|
case ScenarioProtectRecord.sid:
|
||||||
|
checkNotPresent(_scenarioProtectRecord);
|
||||||
|
_scenarioProtectRecord = (ScenarioProtectRecord) rs.getNext();
|
||||||
|
break;
|
||||||
|
case PasswordRecord.sid:
|
||||||
|
checkNotPresent(_passwordRecord);
|
||||||
|
_passwordRecord = (PasswordRecord) rs.getNext();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// all other record types are not part of the PageSettingsBlock
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNotPresent(Record rec) {
|
||||||
|
if (rec != null) {
|
||||||
|
throw new RecordFormatException("Duplicate PageSettingsBlock record (sid=0x"
|
||||||
|
+ Integer.toHexString(rec.getSid()) + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void visitContainedRecords(RecordVisitor rv) {
|
||||||
|
// Replicates record order from Excel 2007, though this is not critical
|
||||||
|
|
||||||
|
visitIfPresent(_protectRecord, rv);
|
||||||
|
visitIfPresent(_objectProtectRecord, rv);
|
||||||
|
visitIfPresent(_scenarioProtectRecord, rv);
|
||||||
|
visitIfPresent(_passwordRecord, rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void visitIfPresent(Record r, RecordVisitor rv) {
|
||||||
|
if (r != null) {
|
||||||
|
rv.visitRecord(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordRecord getPasswordRecord() {
|
||||||
|
return _passwordRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScenarioProtectRecord getHCenter() {
|
||||||
|
return _scenarioProtectRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method reads {@link WorksheetProtectionBlock} records from the supplied RecordStream
|
||||||
|
* until the first non-WorksheetProtectionBlock record is encountered. As each record is read,
|
||||||
|
* it is incorporated into this WorksheetProtectionBlock.
|
||||||
|
* <p/>
|
||||||
|
* As per the OOO documentation, the protection block records can be expected to be written
|
||||||
|
* together (with no intervening records), but earlier versions of POI (prior to Jun 2009)
|
||||||
|
* didn't do this. Workbooks with sheet protection created by those earlier POI versions
|
||||||
|
* seemed to be valid (Excel opens them OK). So PO allows continues to support reading of files
|
||||||
|
* with non continuous worksheet protection blocks.
|
||||||
|
*
|
||||||
|
* <p/>
|
||||||
|
* <b>Note</b> - when POI writes out this WorksheetProtectionBlock, the records will always be
|
||||||
|
* written in one consolidated block (in the standard ordering) regardless of how scattered the
|
||||||
|
* records were when they were originally read.
|
||||||
|
*/
|
||||||
|
public void addRecords(RecordStream rs) {
|
||||||
|
while (true) {
|
||||||
|
if (!readARecord(rs)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the ProtectRecord. If one is not contained in the sheet, then one
|
||||||
|
* is created.
|
||||||
|
*/
|
||||||
|
private ProtectRecord getProtect() {
|
||||||
|
if (_protectRecord == null) {
|
||||||
|
_protectRecord = new ProtectRecord(false);
|
||||||
|
}
|
||||||
|
return _protectRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the PasswordRecord. If one is not contained in the sheet, then
|
||||||
|
* one is created.
|
||||||
|
*/
|
||||||
|
private PasswordRecord getPassword() {
|
||||||
|
if (_passwordRecord == null) {
|
||||||
|
_passwordRecord = createPassword();
|
||||||
|
}
|
||||||
|
return _passwordRecord;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* protect a spreadsheet with a password (not encrypted, just sets protect
|
||||||
|
* flags and the password.
|
||||||
|
*
|
||||||
|
* @param password to set. Pass <code>null</code> to remove all protection
|
||||||
|
* @param shouldProtectObjects are protected
|
||||||
|
* @param shouldProtectScenarios are protected
|
||||||
|
*/
|
||||||
|
public void protectSheet(String password, boolean shouldProtectObjects,
|
||||||
|
boolean shouldProtectScenarios) {
|
||||||
|
if (password == null) {
|
||||||
|
_passwordRecord = null;
|
||||||
|
_protectRecord = null;
|
||||||
|
_objectProtectRecord = null;
|
||||||
|
_scenarioProtectRecord = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProtectRecord prec = getProtect();
|
||||||
|
PasswordRecord pass = getPassword();
|
||||||
|
prec.setProtect(true);
|
||||||
|
pass.setPassword(PasswordRecord.hashPassword(password));
|
||||||
|
if (_objectProtectRecord == null && shouldProtectObjects) {
|
||||||
|
ObjectProtectRecord rec = createObjectProtect();
|
||||||
|
rec.setProtect(true);
|
||||||
|
_objectProtectRecord = rec;
|
||||||
|
}
|
||||||
|
if (_scenarioProtectRecord == null && shouldProtectScenarios) {
|
||||||
|
ScenarioProtectRecord srec = createScenarioProtect();
|
||||||
|
srec.setProtect(true);
|
||||||
|
_scenarioProtectRecord = srec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSheetProtected() {
|
||||||
|
return _protectRecord != null && _protectRecord.getProtect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isObjectProtected() {
|
||||||
|
return _objectProtectRecord != null && _objectProtectRecord.getProtect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isScenarioProtected() {
|
||||||
|
return _scenarioProtectRecord != null && _scenarioProtectRecord.getProtect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates an ObjectProtect record with protect set to false.
|
||||||
|
*/
|
||||||
|
private static ObjectProtectRecord createObjectProtect() {
|
||||||
|
ObjectProtectRecord retval = new ObjectProtectRecord();
|
||||||
|
retval.setProtect(false);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a ScenarioProtect record with protect set to false.
|
||||||
|
*/
|
||||||
|
private static ScenarioProtectRecord createScenarioProtect() {
|
||||||
|
ScenarioProtectRecord retval = new ScenarioProtectRecord();
|
||||||
|
retval.setProtect(false);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* creates a Password record with password set to 0x0000.
|
||||||
|
*/
|
||||||
|
private static PasswordRecord createPassword() {
|
||||||
|
return new PasswordRecord(0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPasswordHash() {
|
||||||
|
if (_passwordRecord == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return _passwordRecord.getPassword();
|
||||||
|
}
|
||||||
|
}
|
@ -44,6 +44,7 @@ import org.apache.poi.hssf.record.SCLRecord;
|
|||||||
import org.apache.poi.hssf.record.WSBoolRecord;
|
import org.apache.poi.hssf.record.WSBoolRecord;
|
||||||
import org.apache.poi.hssf.record.WindowTwoRecord;
|
import org.apache.poi.hssf.record.WindowTwoRecord;
|
||||||
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
import org.apache.poi.hssf.record.aggregates.DataValidityTable;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
|
||||||
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
import org.apache.poi.hssf.record.formula.FormulaShifter;
|
||||||
import org.apache.poi.hssf.util.PaneInformation;
|
import org.apache.poi.hssf.util.PaneInformation;
|
||||||
import org.apache.poi.hssf.util.Region;
|
import org.apache.poi.hssf.util.Region;
|
||||||
@ -126,7 +127,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* @return the parent workbook
|
* @return the parent workbook
|
||||||
*/
|
*/
|
||||||
public HSSFWorkbook getWorkbook(){
|
public HSSFWorkbook getWorkbook(){
|
||||||
return _workbook;
|
return _workbook;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -162,7 +163,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
hrow = getRow( cval.getRow() );
|
hrow = getRow( cval.getRow() );
|
||||||
lastrow = hrow;
|
lastrow = hrow;
|
||||||
if (hrow == null) {
|
if (hrow == null) {
|
||||||
// Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords
|
// Some tools (like Perl module Spreadsheet::WriteExcel - bug 41187) skip the RowRecords
|
||||||
// Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too.
|
// Excel, OpenOffice.org and GoogleDocs are all OK with this, so POI should be too.
|
||||||
if (rowRecordsAlreadyPresent) {
|
if (rowRecordsAlreadyPresent) {
|
||||||
// if at least one row record is present, all should be present.
|
// if at least one row record is present, all should be present.
|
||||||
@ -180,7 +181,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
if (log.check( POILogger.DEBUG ))
|
if (log.check( POILogger.DEBUG ))
|
||||||
log.log( DEBUG, "record took ",
|
log.log( DEBUG, "record took ",
|
||||||
new Long( System.currentTimeMillis() - cellstart ) );
|
new Long( System.currentTimeMillis() - cellstart ) );
|
||||||
|
|
||||||
}
|
}
|
||||||
if (log.check( POILogger.DEBUG ))
|
if (log.check( POILogger.DEBUG ))
|
||||||
log.log(DEBUG, "total sheet cell creation took ",
|
log.log(DEBUG, "total sheet cell creation took ",
|
||||||
@ -340,12 +341,12 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* Gets the number last row on the sheet.
|
* Gets the number last row on the sheet.
|
||||||
* Owing to idiosyncrasies in the excel file
|
* Owing to idiosyncrasies in the excel file
|
||||||
* format, if the result of calling this method
|
* format, if the result of calling this method
|
||||||
* is zero, you can't tell if that means there
|
* is zero, you can't tell if that means there
|
||||||
* are zero rows on the sheet, or one at
|
* are zero rows on the sheet, or one at
|
||||||
* position zero. For that case, additionally
|
* position zero. For that case, additionally
|
||||||
* call {@link #getPhysicalNumberOfRows()} to
|
* call {@link #getPhysicalNumberOfRows()} to
|
||||||
* tell if there is a row at position zero
|
* tell if there is a row at position zero
|
||||||
* or not.
|
* or not.
|
||||||
* @return the number of the last row contained in this sheet, zero based.
|
* @return the number of the last row contained in this sheet, zero based.
|
||||||
*/
|
*/
|
||||||
public int getLastRowNum() {
|
public int getLastRowNum() {
|
||||||
@ -504,20 +505,20 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
{
|
{
|
||||||
_sheet.setDefaultRowHeight((short) (height * 20));
|
_sheet.setDefaultRowHeight((short) (height * 20));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the HSSFCellStyle that applies to the given
|
* Returns the HSSFCellStyle that applies to the given
|
||||||
* (0 based) column, or null if no style has been
|
* (0 based) column, or null if no style has been
|
||||||
* set for that column
|
* set for that column
|
||||||
*/
|
*/
|
||||||
public HSSFCellStyle getColumnStyle(int column) {
|
public HSSFCellStyle getColumnStyle(int column) {
|
||||||
short styleIndex = _sheet.getXFIndexForColAt((short)column);
|
short styleIndex = _sheet.getXFIndexForColAt((short)column);
|
||||||
|
|
||||||
if(styleIndex == 0xf) {
|
if(styleIndex == 0xf) {
|
||||||
// None set
|
// None set
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtendedFormatRecord xf = _book.getExFormatAt(styleIndex);
|
ExtendedFormatRecord xf = _book.getExFormatAt(styleIndex);
|
||||||
return new HSSFCellStyle(styleIndex, xf, _book);
|
return new HSSFCellStyle(styleIndex, xf, _book);
|
||||||
}
|
}
|
||||||
@ -660,8 +661,8 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
*/
|
*/
|
||||||
public Region getMergedRegionAt(int index) {
|
public Region getMergedRegionAt(int index) {
|
||||||
CellRangeAddress cra = getMergedRegion(index);
|
CellRangeAddress cra = getMergedRegion(index);
|
||||||
|
|
||||||
return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
|
return new Region(cra.getFirstRow(), (short)cra.getFirstColumn(),
|
||||||
cra.getLastRow(), (short)cra.getLastColumn());
|
cra.getLastRow(), (short)cra.getLastColumn());
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -858,7 +859,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* @param value whether to display or hide all zero values on the worksheet
|
* @param value whether to display or hide all zero values on the worksheet
|
||||||
*/
|
*/
|
||||||
public void setDisplayZeros(boolean value){
|
public void setDisplayZeros(boolean value){
|
||||||
_sheet.getWindowTwo().setDisplayZeros(value);
|
_sheet.getWindowTwo().setDisplayZeros(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -967,19 +968,22 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
_sheet.getPageSettings().setMargin(margin, size);
|
_sheet.getPageSettings().setMargin(margin, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WorksheetProtectionBlock getProtectionBlock() {
|
||||||
|
return _sheet.getProtectionBlock();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Answer whether protection is enabled or disabled
|
* Answer whether protection is enabled or disabled
|
||||||
* @return true => protection enabled; false => protection disabled
|
* @return true => protection enabled; false => protection disabled
|
||||||
*/
|
*/
|
||||||
public boolean getProtect() {
|
public boolean getProtect() {
|
||||||
return getSheet().isProtected()[0];
|
return getProtectionBlock().isSheetProtected();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return hashed password
|
* @return hashed password
|
||||||
*/
|
*/
|
||||||
public short getPassword() {
|
public short getPassword() {
|
||||||
return (short)getSheet().getPassword().getPassword();
|
return (short)getProtectionBlock().getPasswordHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -987,7 +991,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* @return true => protection enabled; false => protection disabled
|
* @return true => protection enabled; false => protection disabled
|
||||||
*/
|
*/
|
||||||
public boolean getObjectProtect() {
|
public boolean getObjectProtect() {
|
||||||
return getSheet().isProtected()[1];
|
return getProtectionBlock().isObjectProtected();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -995,24 +999,14 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* @return true => protection enabled; false => protection disabled
|
* @return true => protection enabled; false => protection disabled
|
||||||
*/
|
*/
|
||||||
public boolean getScenarioProtect() {
|
public boolean getScenarioProtect() {
|
||||||
return getSheet().isProtected()[2];
|
return getProtectionBlock().isScenarioProtected();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the protection on enabled or disabled
|
|
||||||
* @param protect true => protection enabled; false => protection disabled
|
|
||||||
* @deprecated (Jul 2007) use {@link #protectSheet(String)}
|
|
||||||
*/
|
|
||||||
public void setProtect(boolean protect) {
|
|
||||||
getSheet().getProtect().setProtect(protect);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the protection enabled as well as the password
|
* Sets the protection enabled as well as the password
|
||||||
* @param password to set for protection
|
* @param password to set for protection. Pass <code>null</code> to remove protection
|
||||||
*/
|
*/
|
||||||
public void protectSheet(String password) {
|
public void protectSheet(String password) {
|
||||||
getSheet().protectSheet(password, true, true); //protect objs&scenarios(normal)
|
getProtectionBlock().protectSheet(password, true, true); //protect objs&scenarios(normal)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1153,7 +1147,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
public void shiftRows( int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
|
public void shiftRows( int startRow, int endRow, int n, boolean copyRowHeight, boolean resetOriginalRowHeight) {
|
||||||
shiftRows(startRow, endRow, n, copyRowHeight, resetOriginalRowHeight, true);
|
shiftRows(startRow, endRow, n, copyRowHeight, resetOriginalRowHeight, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shifts rows between startRow and endRow n number of rows.
|
* Shifts rows between startRow and endRow n number of rows.
|
||||||
* If you use a negative number, it will shift rows up.
|
* If you use a negative number, it will shift rows up.
|
||||||
@ -1171,7 +1165,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* @param resetOriginalRowHeight whether to set the original row's height to the default
|
* @param resetOriginalRowHeight whether to set the original row's height to the default
|
||||||
* @param moveComments whether to move comments at the same time as the cells they are attached to
|
* @param moveComments whether to move comments at the same time as the cells they are attached to
|
||||||
*/
|
*/
|
||||||
public void shiftRows(int startRow, int endRow, int n,
|
public void shiftRows(int startRow, int endRow, int n,
|
||||||
boolean copyRowHeight, boolean resetOriginalRowHeight, boolean moveComments) {
|
boolean copyRowHeight, boolean resetOriginalRowHeight, boolean moveComments) {
|
||||||
int s, inc;
|
int s, inc;
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
@ -1183,7 +1177,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
}
|
}
|
||||||
NoteRecord[] noteRecs;
|
NoteRecord[] noteRecs;
|
||||||
if (moveComments) {
|
if (moveComments) {
|
||||||
noteRecs = _sheet.getNoteRecords();
|
noteRecs = _sheet.getNoteRecords();
|
||||||
} else {
|
} else {
|
||||||
noteRecs = NoteRecord.EMPTY_ARRAY;
|
noteRecs = NoteRecord.EMPTY_ARRAY;
|
||||||
}
|
}
|
||||||
@ -1197,10 +1191,10 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
if ( row2Replace == null )
|
if ( row2Replace == null )
|
||||||
row2Replace = createRow( rowNum + n );
|
row2Replace = createRow( rowNum + n );
|
||||||
|
|
||||||
|
|
||||||
// Remove all the old cells from the row we'll
|
// Remove all the old cells from the row we'll
|
||||||
// be writing too, before we start overwriting
|
// be writing too, before we start overwriting
|
||||||
// any cells. This avoids issues with cells
|
// any cells. This avoids issues with cells
|
||||||
// changing type, and records not being correctly
|
// changing type, and records not being correctly
|
||||||
// overwritten
|
// overwritten
|
||||||
row2Replace.removeAllCells();
|
row2Replace.removeAllCells();
|
||||||
@ -1235,7 +1229,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
}
|
}
|
||||||
// Now zap all the cells in the source row
|
// Now zap all the cells in the source row
|
||||||
row.removeAllCells();
|
row.removeAllCells();
|
||||||
|
|
||||||
// Move comments from the source row to the
|
// Move comments from the source row to the
|
||||||
// destination row. Note that comments can
|
// destination row. Note that comments can
|
||||||
// exist for cells which are null
|
// exist for cells which are null
|
||||||
@ -1476,10 +1470,10 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
for (Iterator<EscherRecord> iterator = escherRecords.iterator(); iterator.hasNext();) {
|
for (Iterator<EscherRecord> iterator = escherRecords.iterator(); iterator.hasNext();) {
|
||||||
EscherRecord escherRecord = iterator.next();
|
EscherRecord escherRecord = iterator.next();
|
||||||
if (fat) {
|
if (fat) {
|
||||||
System.out.println(escherRecord.toString());
|
System.out.println(escherRecord.toString());
|
||||||
} else {
|
} else {
|
||||||
escherRecord.display(w, 0);
|
escherRecord.display(w, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.flush();
|
w.flush();
|
||||||
}
|
}
|
||||||
@ -1533,7 +1527,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
|
EscherAggregate agg = (EscherAggregate) _sheet.findFirstRecordBySid(EscherAggregate.sid);
|
||||||
return agg;
|
return agg;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the top-level drawing patriach, if there is
|
* Returns the top-level drawing patriach, if there is
|
||||||
* one.
|
* one.
|
||||||
@ -1549,7 +1543,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
public HSSFPatriarch getDrawingPatriarch() {
|
public HSSFPatriarch getDrawingPatriarch() {
|
||||||
EscherAggregate agg = getDrawingEscherAggregate();
|
EscherAggregate agg = getDrawingEscherAggregate();
|
||||||
if(agg == null) return null;
|
if(agg == null) return null;
|
||||||
|
|
||||||
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
|
HSSFPatriarch patriarch = new HSSFPatriarch(this, agg);
|
||||||
agg.setPatriarch(patriarch);
|
agg.setPatriarch(patriarch);
|
||||||
|
|
||||||
@ -1649,7 +1643,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
public void autoSizeColumn(int column) {
|
public void autoSizeColumn(int column) {
|
||||||
autoSizeColumn(column, false);
|
autoSizeColumn(column, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the column width to fit the contents.
|
* Adjusts the column width to fit the contents.
|
||||||
*
|
*
|
||||||
@ -1657,9 +1651,9 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* normally only be called once per column, at the end of your
|
* normally only be called once per column, at the end of your
|
||||||
* processing.
|
* processing.
|
||||||
*
|
*
|
||||||
* You can specify whether the content of merged cells should be considered or ignored.
|
* You can specify whether the content of merged cells should be considered or ignored.
|
||||||
* Default is to ignore merged cells.
|
* Default is to ignore merged cells.
|
||||||
*
|
*
|
||||||
* @param column the column index
|
* @param column the column index
|
||||||
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
* @param useMergedCells whether to use the contents of merged cells when calculating the width of the column
|
||||||
*/
|
*/
|
||||||
@ -1672,13 +1666,13 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
* '0' looks to be a good choice.
|
* '0' looks to be a good choice.
|
||||||
*/
|
*/
|
||||||
char defaultChar = '0';
|
char defaultChar = '0';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is the multiple that the font height is scaled by when determining the
|
* This is the multiple that the font height is scaled by when determining the
|
||||||
* boundary of rotated text.
|
* boundary of rotated text.
|
||||||
*/
|
*/
|
||||||
double fontHeightMultiple = 2.0;
|
double fontHeightMultiple = 2.0;
|
||||||
|
|
||||||
FontRenderContext frc = new FontRenderContext(null, true, true);
|
FontRenderContext frc = new FontRenderContext(null, true, true);
|
||||||
|
|
||||||
HSSFWorkbook wb = new HSSFWorkbook(_book);
|
HSSFWorkbook wb = new HSSFWorkbook(_book);
|
||||||
@ -1704,7 +1698,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
CellRangeAddress region = getMergedRegion(i);
|
CellRangeAddress region = getMergedRegion(i);
|
||||||
if (containsCell(region, row.getRowNum(), column)) {
|
if (containsCell(region, row.getRowNum(), column)) {
|
||||||
if (!useMergedCells) {
|
if (!useMergedCells) {
|
||||||
// If we're not using merged cells, skip this one and move on to the next.
|
// If we're not using merged cells, skip this one and move on to the next.
|
||||||
continue rows;
|
continue rows;
|
||||||
}
|
}
|
||||||
cell = row.getCell(region.getFirstColumn());
|
cell = row.getCell(region.getFirstColumn());
|
||||||
@ -1715,7 +1709,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
HSSFCellStyle style = cell.getCellStyle();
|
HSSFCellStyle style = cell.getCellStyle();
|
||||||
int cellType = cell.getCellType();
|
int cellType = cell.getCellType();
|
||||||
if(cellType == HSSFCell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
|
if(cellType == HSSFCell.CELL_TYPE_FORMULA) cellType = cell.getCachedFormulaResultType();
|
||||||
|
|
||||||
HSSFFont font = wb.getFontAt(style.getFontIndex());
|
HSSFFont font = wb.getFontAt(style.getFontIndex());
|
||||||
|
|
||||||
if (cellType == HSSFCell.CELL_TYPE_STRING) {
|
if (cellType == HSSFCell.CELL_TYPE_STRING) {
|
||||||
@ -1836,9 +1830,9 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
|
|||||||
if(c != null) {
|
if(c != null) {
|
||||||
return c.getCellComment();
|
return c.getCellComment();
|
||||||
}
|
}
|
||||||
// No cell, so you will get new
|
// No cell, so you will get new
|
||||||
// objects every time, sorry...
|
// objects every time, sorry...
|
||||||
return HSSFCell.findCellComment(_sheet, row, column);
|
return HSSFCell.findCellComment(_sheet, row, column);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -644,15 +644,14 @@ public final class TestSheet extends TestCase {
|
|||||||
Sheet sheet = Sheet.createSheet();
|
Sheet sheet = Sheet.createSheet();
|
||||||
|
|
||||||
List<RecordBase> sheetRecs = sheet.getRecords();
|
List<RecordBase> sheetRecs = sheet.getRecords();
|
||||||
assertEquals(22, sheetRecs.size());
|
assertEquals(23, sheetRecs.size());
|
||||||
|
|
||||||
FormulaShifter shifter = FormulaShifter.createForRowShift(0, 0, 0, 1);
|
FormulaShifter shifter = FormulaShifter.createForRowShift(0, 0, 0, 1);
|
||||||
sheet.updateFormulasAfterCellShift(shifter, 0);
|
sheet.updateFormulasAfterCellShift(shifter, 0);
|
||||||
if (sheetRecs.size() == 23 && sheetRecs.get(21) instanceof ConditionalFormattingTable) {
|
if (sheetRecs.size() == 24 && sheetRecs.get(22) instanceof ConditionalFormattingTable) {
|
||||||
throw new AssertionFailedError("Identified bug 46547a");
|
throw new AssertionFailedError("Identified bug 46547a");
|
||||||
}
|
}
|
||||||
assertEquals(22, sheetRecs.size());
|
assertEquals(23, sheetRecs.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Bug 46547 happened when attempting to add conditional formatting to a sheet
|
* Bug 46547 happened when attempting to add conditional formatting to a sheet
|
||||||
|
@ -28,7 +28,10 @@ import org.apache.poi.hssf.HSSFITestDataProvider;
|
|||||||
import org.apache.poi.hssf.model.Sheet;
|
import org.apache.poi.hssf.model.Sheet;
|
||||||
import org.apache.poi.hssf.model.DrawingManager2;
|
import org.apache.poi.hssf.model.DrawingManager2;
|
||||||
import org.apache.poi.hssf.record.*;
|
import org.apache.poi.hssf.record.*;
|
||||||
|
import org.apache.poi.hssf.record.aggregates.WorksheetProtectionBlock;
|
||||||
|
import org.apache.poi.hssf.usermodel.RecordInspector.RecordCollector;
|
||||||
import org.apache.poi.ss.util.CellRangeAddress;
|
import org.apache.poi.ss.util.CellRangeAddress;
|
||||||
|
import org.apache.poi.ss.util.CellRangeAddressList;
|
||||||
import org.apache.poi.ss.usermodel.BaseTestSheet;
|
import org.apache.poi.ss.usermodel.BaseTestSheet;
|
||||||
import org.apache.poi.ddf.EscherDgRecord;
|
import org.apache.poi.ddf.EscherDgRecord;
|
||||||
|
|
||||||
@ -125,7 +128,7 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
s.setRowSumsRight(true);
|
s.setRowSumsRight(true);
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
assertEquals(true, record.getAlternateExpression()); //sheet.setRowSumsBelow alters this field too
|
assertEquals(true, record.getAlternateExpression()); //sheet.setRowSumsBelow alters this field too
|
||||||
assertEquals(false, record.getAlternateFormula());
|
assertEquals(false, record.getAlternateFormula());
|
||||||
assertEquals(true, record.getAutobreaks());
|
assertEquals(true, record.getAutobreaks());
|
||||||
assertEquals(true, record.getDialog());
|
assertEquals(true, record.getDialog());
|
||||||
@ -300,37 +303,104 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
/**
|
/**
|
||||||
* Test that the ProtectRecord is included when creating or cloning a sheet
|
* Test that the ProtectRecord is included when creating or cloning a sheet
|
||||||
*/
|
*/
|
||||||
public void testProtect() {
|
public void testCloneWithProtect() {
|
||||||
|
String passwordA = "secrect";
|
||||||
|
int expectedHashA = -6810;
|
||||||
|
String passwordB = "admin";
|
||||||
|
int expectedHashB = -14556;
|
||||||
HSSFWorkbook workbook = new HSSFWorkbook();
|
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||||
HSSFSheet hssfSheet = workbook.createSheet();
|
HSSFSheet hssfSheet = workbook.createSheet();
|
||||||
Sheet sheet = hssfSheet.getSheet();
|
hssfSheet.protectSheet(passwordA);
|
||||||
ProtectRecord protect = sheet.getProtect();
|
|
||||||
|
|
||||||
assertFalse(protect.getProtect());
|
assertEquals(expectedHashA, hssfSheet.getSheet().getProtectionBlock().getPasswordHash());
|
||||||
|
|
||||||
// This will tell us that cloneSheet, and by extension,
|
// Clone the sheet, and make sure the password hash is preserved
|
||||||
// the list forms of createSheet leave us with an accessible
|
HSSFSheet sheet2 = workbook.cloneSheet(0);
|
||||||
// ProtectRecord.
|
assertEquals(expectedHashA, sheet2.getSheet().getProtectionBlock().getPasswordHash());
|
||||||
hssfSheet.protectSheet("secret");
|
|
||||||
Sheet cloned = sheet.cloneSheet();
|
// change the password on the first sheet
|
||||||
assertNotNull(cloned.getProtect());
|
hssfSheet.protectSheet(passwordB);
|
||||||
assertTrue(hssfSheet.getProtect());
|
assertEquals(expectedHashB, hssfSheet.getSheet().getProtectionBlock().getPasswordHash());
|
||||||
|
// but the cloned sheet's password should remain unchanged
|
||||||
|
assertEquals(expectedHashA, sheet2.getSheet().getProtectionBlock().getPasswordHash());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testProtectSheet() {
|
public void testProtectSheet() {
|
||||||
short expected = (short)0xfef1;
|
int expectedHash = (short)0xfef1;
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
HSSFSheet s = wb.createSheet();
|
HSSFSheet s = wb.createSheet();
|
||||||
s.protectSheet("abcdefghij");
|
s.protectSheet("abcdefghij");
|
||||||
Sheet sheet = s.getSheet();
|
WorksheetProtectionBlock pb = s.getSheet().getProtectionBlock();
|
||||||
ProtectRecord protect = sheet.getProtect();
|
assertTrue("protection should be on", pb.isSheetProtected());
|
||||||
PasswordRecord pass = sheet.getPassword();
|
assertTrue("object protection should be on",pb.isObjectProtected());
|
||||||
assertTrue("protection should be on",protect.getProtect());
|
assertTrue("scenario protection should be on",pb.isScenarioProtected());
|
||||||
assertTrue("object protection should be on",sheet.isProtected()[1]);
|
assertEquals("well known value for top secret hash should be "+Integer.toHexString(expectedHash).substring(4), expectedHash, pb.getPasswordHash());
|
||||||
assertTrue("scenario protection should be on",sheet.isProtected()[2]);
|
|
||||||
assertEquals("well known value for top secret hash should be "+Integer.toHexString(expected).substring(4),expected,pass.getPassword());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link PasswordRecord} belongs with the rest of the Worksheet Protection Block
|
||||||
|
* (which should be before {@link DimensionsRecord}).
|
||||||
|
*/
|
||||||
|
public void testProtectSheetRecordOrder_bug47363a() {
|
||||||
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
|
HSSFSheet s = wb.createSheet();
|
||||||
|
s.protectSheet("secret");
|
||||||
|
RecordCollector rc = new RecordCollector();
|
||||||
|
s.getSheet().visitContainedRecords(rc, 0);
|
||||||
|
Record[] recs = rc.getRecords();
|
||||||
|
int nRecs = recs.length;
|
||||||
|
if (recs[nRecs-2] instanceof PasswordRecord && recs[nRecs-5] instanceof DimensionsRecord) {
|
||||||
|
throw new AssertionFailedError("Identified bug 47363a - PASSWORD after DIMENSION");
|
||||||
|
}
|
||||||
|
// Check that protection block is together, and before DIMENSION
|
||||||
|
confirmRecordClass(recs, nRecs-4, DimensionsRecord.class);
|
||||||
|
confirmRecordClass(recs, nRecs-9, ProtectRecord.class);
|
||||||
|
confirmRecordClass(recs, nRecs-8, ObjectProtectRecord.class);
|
||||||
|
confirmRecordClass(recs, nRecs-7, ScenarioProtectRecord.class);
|
||||||
|
confirmRecordClass(recs, nRecs-6, PasswordRecord.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void confirmRecordClass(Record[] recs, int index, Class<? extends Record> cls) {
|
||||||
|
if (recs.length <= index) {
|
||||||
|
throw new AssertionFailedError("Expected (" + cls.getName() + ") at index "
|
||||||
|
+ index + " but array length is " + recs.length + ".");
|
||||||
|
}
|
||||||
|
assertEquals(cls, recs[index].getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* There should be no problem with adding data validations after sheet protection
|
||||||
|
*/
|
||||||
|
public void testDvProtectionOrder_bug47363b() {
|
||||||
|
HSSFWorkbook workbook = new HSSFWorkbook();
|
||||||
|
HSSFSheet sheet = workbook.createSheet("Sheet1");
|
||||||
|
sheet.protectSheet("secret");
|
||||||
|
|
||||||
|
DVConstraint dvc = DVConstraint.createNumericConstraint(DVConstraint.ValidationType.INTEGER,
|
||||||
|
DVConstraint.OperatorType.BETWEEN, "10", "100");
|
||||||
|
CellRangeAddressList numericCellAddressList = new CellRangeAddressList(0, 0, 1, 1);
|
||||||
|
HSSFDataValidation dv = new HSSFDataValidation(numericCellAddressList, dvc);
|
||||||
|
try {
|
||||||
|
sheet.addValidationData(dv);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
String expMsg = "Unexpected (org.apache.poi.hssf.record.PasswordRecord) while looking for DV Table insert pos";
|
||||||
|
if (expMsg.equals(e.getMessage())) {
|
||||||
|
throw new AssertionFailedError("Identified bug 47363b");
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
RecordCollector rc;
|
||||||
|
rc = new RecordCollector();
|
||||||
|
sheet.getSheet().visitContainedRecords(rc, 0);
|
||||||
|
int nRecsWithProtection = rc.getRecords().length;
|
||||||
|
|
||||||
|
sheet.protectSheet(null);
|
||||||
|
rc = new RecordCollector();
|
||||||
|
sheet.getSheet().visitContainedRecords(rc, 0);
|
||||||
|
int nRecsWithoutProtection = rc.getRecords().length;
|
||||||
|
|
||||||
|
assertEquals(4, nRecsWithProtection - nRecsWithoutProtection);
|
||||||
|
}
|
||||||
|
|
||||||
public void testZoom() {
|
public void testZoom() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
@ -674,16 +744,16 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
|
|
||||||
//TODO: check shapeId in the cloned sheet
|
//TODO: check shapeId in the cloned sheet
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* POI now (Sep 2008) allows sheet names longer than 31 chars (for other apps besides Excel).
|
* POI now (Sep 2008) allows sheet names longer than 31 chars (for other apps besides Excel).
|
||||||
* Since Excel silently truncates to 31, make sure that POI enforces uniqueness on the first
|
* Since Excel silently truncates to 31, make sure that POI enforces uniqueness on the first
|
||||||
* 31 chars.
|
* 31 chars.
|
||||||
*/
|
*/
|
||||||
public void testLongSheetNames() {
|
public void testLongSheetNames() {
|
||||||
HSSFWorkbook wb = new HSSFWorkbook();
|
HSSFWorkbook wb = new HSSFWorkbook();
|
||||||
final String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars
|
final String SAME_PREFIX = "A123456789B123456789C123456789"; // 30 chars
|
||||||
|
|
||||||
wb.createSheet(SAME_PREFIX + "Dxxxx");
|
wb.createSheet(SAME_PREFIX + "Dxxxx");
|
||||||
try {
|
try {
|
||||||
wb.createSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char
|
wb.createSheet(SAME_PREFIX + "Dyyyy"); // identical up to the 32nd char
|
||||||
@ -693,7 +763,7 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
}
|
}
|
||||||
wb.createSheet(SAME_PREFIX + "Exxxx"); // OK - differs in the 31st char
|
wb.createSheet(SAME_PREFIX + "Exxxx"); // OK - differs in the 31st char
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that we can read existing column styles
|
* Tests that we can read existing column styles
|
||||||
*/
|
*/
|
||||||
@ -701,17 +771,17 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
HSSFWorkbook wbNone = HSSFTestDataSamples.openSampleWorkbook("ColumnStyleNone.xls");
|
HSSFWorkbook wbNone = HSSFTestDataSamples.openSampleWorkbook("ColumnStyleNone.xls");
|
||||||
HSSFWorkbook wbSimple = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dp.xls");
|
HSSFWorkbook wbSimple = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dp.xls");
|
||||||
HSSFWorkbook wbComplex = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dpColoured.xls");
|
HSSFWorkbook wbComplex = HSSFTestDataSamples.openSampleWorkbook("ColumnStyle1dpColoured.xls");
|
||||||
|
|
||||||
// Presence / absence checks
|
// Presence / absence checks
|
||||||
assertNull(wbNone.getSheetAt(0).getColumnStyle(0));
|
assertNull(wbNone.getSheetAt(0).getColumnStyle(0));
|
||||||
assertNull(wbNone.getSheetAt(0).getColumnStyle(1));
|
assertNull(wbNone.getSheetAt(0).getColumnStyle(1));
|
||||||
|
|
||||||
assertNull(wbSimple.getSheetAt(0).getColumnStyle(0));
|
assertNull(wbSimple.getSheetAt(0).getColumnStyle(0));
|
||||||
assertNotNull(wbSimple.getSheetAt(0).getColumnStyle(1));
|
assertNotNull(wbSimple.getSheetAt(0).getColumnStyle(1));
|
||||||
|
|
||||||
assertNull(wbComplex.getSheetAt(0).getColumnStyle(0));
|
assertNull(wbComplex.getSheetAt(0).getColumnStyle(0));
|
||||||
assertNotNull(wbComplex.getSheetAt(0).getColumnStyle(1));
|
assertNotNull(wbComplex.getSheetAt(0).getColumnStyle(1));
|
||||||
|
|
||||||
// Details checks
|
// Details checks
|
||||||
HSSFCellStyle bs = wbSimple.getSheetAt(0).getColumnStyle(1);
|
HSSFCellStyle bs = wbSimple.getSheetAt(0).getColumnStyle(1);
|
||||||
assertEquals(62, bs.getIndex());
|
assertEquals(62, bs.getIndex());
|
||||||
@ -721,8 +791,8 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
assertEquals(8, bs.getFont(wbSimple).getColor());
|
assertEquals(8, bs.getFont(wbSimple).getColor());
|
||||||
assertFalse(bs.getFont(wbSimple).getItalic());
|
assertFalse(bs.getFont(wbSimple).getItalic());
|
||||||
assertEquals(HSSFFont.BOLDWEIGHT_NORMAL, bs.getFont(wbSimple).getBoldweight());
|
assertEquals(HSSFFont.BOLDWEIGHT_NORMAL, bs.getFont(wbSimple).getBoldweight());
|
||||||
|
|
||||||
|
|
||||||
HSSFCellStyle cs = wbComplex.getSheetAt(0).getColumnStyle(1);
|
HSSFCellStyle cs = wbComplex.getSheetAt(0).getColumnStyle(1);
|
||||||
assertEquals(62, cs.getIndex());
|
assertEquals(62, cs.getIndex());
|
||||||
assertEquals("#,##0.0_ ;\\-#,##0.0\\ ", cs.getDataFormatString());
|
assertEquals("#,##0.0_ ;\\-#,##0.0\\ ", cs.getDataFormatString());
|
||||||
@ -732,5 +802,4 @@ public final class TestHSSFSheet extends BaseTestSheet {
|
|||||||
assertFalse(cs.getFont(wbComplex).getItalic());
|
assertFalse(cs.getFont(wbComplex).getItalic());
|
||||||
assertEquals(HSSFFont.BOLDWEIGHT_BOLD, cs.getFont(wbComplex).getBoldweight());
|
assertEquals(HSSFFont.BOLDWEIGHT_BOLD, cs.getFont(wbComplex).getBoldweight());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user