#61363 - Unify escher shape id allocation

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1803483 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Andreas Beeker 2017-07-30 23:11:36 +00:00
parent b3c111a283
commit ff2bcdf62d
14 changed files with 286 additions and 467 deletions

View File

@ -19,6 +19,7 @@ package org.apache.poi.ddf;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -32,38 +33,37 @@ import org.apache.poi.util.RecordFormatException;
public final class EscherDggRecord extends EscherRecord {
public static final short RECORD_ID = (short) 0xF006;
public static final String RECORD_DESCRIPTION = "MsofbtDgg";
private int field_1_shapeIdMax;
// private int field_2_numIdClusters; // for some reason the number of clusters is actually the real number + 1
// for some reason the number of clusters is actually the real number + 1
// private int field_2_numIdClusters;
private int field_3_numShapesSaved;
private int field_4_drawingsSaved;
private FileIdCluster[] field_5_fileIdClusters;
private final List<FileIdCluster> field_5_fileIdClusters = new ArrayList<FileIdCluster>();
private int maxDgId;
public static class FileIdCluster
{
public FileIdCluster( int drawingGroupId, int numShapeIdsUsed )
{
public static class FileIdCluster {
private int field_1_drawingGroupId;
private int field_2_numShapeIdsUsed;
public FileIdCluster( int drawingGroupId, int numShapeIdsUsed ) {
this.field_1_drawingGroupId = drawingGroupId;
this.field_2_numShapeIdsUsed = numShapeIdsUsed;
}
private int field_1_drawingGroupId;
private int field_2_numShapeIdsUsed;
public int getDrawingGroupId()
{
public int getDrawingGroupId() {
return field_1_drawingGroupId;
}
public int getNumShapeIdsUsed()
{
public int getNumShapeIdsUsed() {
return field_2_numShapeIdsUsed;
}
public void incrementShapeId( )
{
this.field_2_numShapeIdsUsed++;
/**
* @return the current used shape ids value and increases it afterwards
*/
private void incrementUsedShapeId() {
field_2_numShapeIdsUsed++;
}
}
@ -77,18 +77,24 @@ public final class EscherDggRecord extends EscherRecord {
size+=4;
field_3_numShapesSaved = LittleEndian.getInt( data, pos + size );size+=4;
field_4_drawingsSaved = LittleEndian.getInt( data, pos + size );size+=4;
field_5_fileIdClusters = new FileIdCluster[(bytesRemaining-size) / 8]; // Can't rely on field_2_numIdClusters
for (int i = 0; i < field_5_fileIdClusters.length; i++)
{
field_5_fileIdClusters[i] = new FileIdCluster(LittleEndian.getInt( data, pos + size ), LittleEndian.getInt( data, pos + size + 4 ));
maxDgId = Math.max(maxDgId, field_5_fileIdClusters[i].getDrawingGroupId());
field_5_fileIdClusters.clear();
// Can't rely on field_2_numIdClusters
int numIdClusters = (bytesRemaining-size) / 8;
for (int i = 0; i < numIdClusters; i++) {
int drawingGroupId = LittleEndian.getInt( data, pos + size );
int numShapeIdsUsed = LittleEndian.getInt( data, pos + size + 4 );
FileIdCluster fic = new FileIdCluster(drawingGroupId, numShapeIdsUsed);
field_5_fileIdClusters.add(fic);
maxDgId = Math.max(maxDgId, drawingGroupId);
size += 8;
}
bytesRemaining -= size;
bytesRemaining -= size;
if (bytesRemaining != 0) {
throw new RecordFormatException("Expecting no remaining data but got " + bytesRemaining + " byte(s).");
}
return 8 + size + bytesRemaining;
return 8 + size;
}
@Override
@ -105,9 +111,10 @@ public final class EscherDggRecord extends EscherRecord {
LittleEndian.putInt( data, pos, getNumIdClusters() ); pos += 4;
LittleEndian.putInt( data, pos, field_3_numShapesSaved ); pos += 4;
LittleEndian.putInt( data, pos, field_4_drawingsSaved ); pos += 4;
for (int i = 0; i < field_5_fileIdClusters.length; i++) {
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_1_drawingGroupId ); pos += 4;
LittleEndian.putInt( data, pos, field_5_fileIdClusters[i].field_2_numShapeIdsUsed ); pos += 4;
for (FileIdCluster fic : field_5_fileIdClusters) {
LittleEndian.putInt( data, pos, fic.getDrawingGroupId() ); pos += 4;
LittleEndian.putInt( data, pos, fic.getNumShapeIdsUsed() ); pos += 4;
}
listener.afterRecordSerialize( pos, getRecordId(), getRecordSize(), this );
@ -116,7 +123,7 @@ public final class EscherDggRecord extends EscherRecord {
@Override
public int getRecordSize() {
return 8 + 16 + (8 * field_5_fileIdClusters.length);
return 8 + 16 + (8 * field_5_fileIdClusters.size());
}
@Override
@ -153,7 +160,7 @@ public final class EscherDggRecord extends EscherRecord {
* @return the number of id clusters + 1
*/
public int getNumIdClusters() {
return (field_5_fileIdClusters == null ? 0 : (field_5_fileIdClusters.length + 1));
return (field_5_fileIdClusters.isEmpty() ? 0 : field_5_fileIdClusters.size() + 1);
}
/**
@ -201,20 +208,11 @@ public final class EscherDggRecord extends EscherRecord {
return maxDgId;
}
/**
* Sets the maximum drawing group ID
*
* @param id the maximum drawing group ID
*/
public void setMaxDrawingGroupId(int id) {
maxDgId = id;
}
/**
* @return the file id clusters
*/
public FileIdCluster[] getFileIdClusters() {
return field_5_fileIdClusters;
return field_5_fileIdClusters.toArray(new FileIdCluster[field_5_fileIdClusters.size()]);
}
/**
@ -223,7 +221,10 @@ public final class EscherDggRecord extends EscherRecord {
* @param fileIdClusters the file id clusters
*/
public void setFileIdClusters(FileIdCluster[] fileIdClusters) {
this.field_5_fileIdClusters = fileIdClusters.clone();
field_5_fileIdClusters.clear();
if (fileIdClusters != null) {
field_5_fileIdClusters.addAll(Arrays.asList(fileIdClusters));
}
}
@ -232,9 +233,11 @@ public final class EscherDggRecord extends EscherRecord {
*
* @param dgId id of the drawing group (stored in the record options)
* @param numShapedUsed initial value of the numShapedUsed field
*
* @return the new {@link FileIdCluster}
*/
public void addCluster(int dgId, int numShapedUsed) {
addCluster(dgId, numShapedUsed, true);
public FileIdCluster addCluster(int dgId, int numShapedUsed) {
return addCluster(dgId, numShapedUsed, true);
}
/**
@ -244,40 +247,98 @@ public final class EscherDggRecord extends EscherRecord {
* @param numShapedUsed initial value of the numShapedUsed field
* @param sort if true then sort clusters by drawing group id.(
* In Excel the clusters are sorted but in PPT they are not)
*
* @return the new {@link FileIdCluster}
*/
public void addCluster( int dgId, int numShapedUsed, boolean sort ) {
List<FileIdCluster> clusters = new ArrayList<FileIdCluster>(Arrays.asList(field_5_fileIdClusters));
clusters.add(new FileIdCluster(dgId, numShapedUsed));
if(sort) {
Collections.sort(clusters, MY_COMP );
}
public FileIdCluster addCluster( int dgId, int numShapedUsed, boolean sort ) {
FileIdCluster ficNew = new FileIdCluster(dgId, numShapedUsed);
field_5_fileIdClusters.add(ficNew);
maxDgId = Math.min(maxDgId, dgId);
field_5_fileIdClusters = clusters.toArray( new FileIdCluster[clusters.size()] );
if (sort) {
sortCluster();
}
return ficNew;
}
private static final Comparator<FileIdCluster> MY_COMP = new Comparator<FileIdCluster>() {
@Override
public int compare(FileIdCluster f1, FileIdCluster f2) {
if (f1.getDrawingGroupId() == f2.getDrawingGroupId()) {
return 0;
private void sortCluster() {
Collections.sort(field_5_fileIdClusters, new Comparator<FileIdCluster>() {
@Override
public int compare(FileIdCluster f1, FileIdCluster f2) {
int dgDif = f1.getDrawingGroupId() - f2.getDrawingGroupId();
int cntDif = f2.getNumShapeIdsUsed() - f1.getNumShapeIdsUsed();
return (dgDif != 0) ? dgDif : cntDif;
}
if (f1.getDrawingGroupId() < f2.getDrawingGroupId()) {
return -1;
}
return +1;
});
}
/**
* Finds the next available (1 based) drawing group id
*
* @return the next available drawing group id
*/
public short findNewDrawingGroupId() {
BitSet bs = new BitSet();
bs.set(0);
for (FileIdCluster fic : field_5_fileIdClusters) {
bs.set(fic.getDrawingGroupId());
}
return (short)bs.nextClearBit(0);
}
/**
* Allocates new shape id for the drawing group
*
* @param drawingGroupId the drawing group id
* @param dg the EscherDgRecord which receives the new shape
* @param sort if true then sort clusters by drawing group id.(
* In Excel the clusters are sorted but in PPT they are not)
*
* @return a new shape id.
*/
public int allocateShapeId(EscherDgRecord dg, boolean sort) {
final short drawingGroupId = dg.getDrawingGroupId();
field_3_numShapesSaved++;
// check for an existing cluster, which has space available
// see 2.2.46 OfficeArtIDCL (cspidCur) for the 1024 limitation
// multiple clusters can belong to the same drawing group
FileIdCluster ficAdd = null;
int index = 1;
for (FileIdCluster fic : field_5_fileIdClusters) {
if (fic.getDrawingGroupId() == drawingGroupId
&& fic.getNumShapeIdsUsed() < 1024) {
ficAdd = fic;
break;
}
index++;
}
};
if (ficAdd == null) {
ficAdd = addCluster( drawingGroupId, 0, sort );
maxDgId = Math.max(maxDgId, drawingGroupId);
}
int shapeId = index*1024 + ficAdd.getNumShapeIdsUsed();
ficAdd.incrementUsedShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 );
dg.setLastMSOSPID( shapeId );
field_1_shapeIdMax = Math.max(field_1_shapeIdMax, shapeId + 1);
return shapeId;
}
@Override
protected Object[][] getAttributeMap() {
List<Object> fldIds = new ArrayList<Object>();
fldIds.add("FileId Clusters");
fldIds.add(field_5_fileIdClusters.length);
if(field_5_fileIdClusters != null) {
for (FileIdCluster fic : field_5_fileIdClusters) {
fldIds.add("Group"+fic.field_1_drawingGroupId);
fldIds.add(fic.field_2_numShapeIdsUsed);
}
fldIds.add(field_5_fileIdClusters.size());
for (FileIdCluster fic : field_5_fileIdClusters) {
fldIds.add("Group"+fic.field_1_drawingGroupId);
fldIds.add(fic.field_2_numShapeIdsUsed);
}
return new Object[][] {

View File

@ -1,155 +0,0 @@
/* ====================================================================
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.model;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherDgRecord;
import java.util.Map;
import java.util.HashMap;
/**
* Provides utilities to manage drawing groups.
*
* @deprecated in POI 3.15-beta2, scheduled for removal in 3.17, use DrawingManager2 instead
*/
@Deprecated
public class DrawingManager
{
EscherDggRecord dgg;
Map<Short, EscherDgRecord> dgMap = new HashMap<Short, EscherDgRecord>(); // key = Short(drawingId), value=EscherDgRecord
public DrawingManager( EscherDggRecord dgg )
{
this.dgg = dgg;
}
public EscherDgRecord createDgRecord()
{
EscherDgRecord dg = new EscherDgRecord();
dg.setRecordId( EscherDgRecord.RECORD_ID );
short dgId = findNewDrawingGroupId();
dg.setOptions( (short) ( dgId << 4 ) );
dg.setNumShapes( 0 );
dg.setLastMSOSPID( -1 );
dgg.addCluster( dgId, 0 );
dgg.setDrawingsSaved( dgg.getDrawingsSaved() + 1 );
dgMap.put( dgId, dg );
return dg;
}
/**
* Allocates new shape id for the new drawing group id.
*
* @param drawingGroupId The drawing group id
* @return a new shape id.
*/
public int allocateShapeId(short drawingGroupId)
{
// Get the last shape id for this drawing group.
EscherDgRecord dg = dgMap.get(drawingGroupId);
int lastShapeId = dg.getLastMSOSPID();
// Have we run out of shapes for this cluster?
int newShapeId = 0;
if (lastShapeId % 1024 == 1023)
{
// Yes:
// Find the starting shape id of the next free cluster
newShapeId = findFreeSPIDBlock();
// Create a new cluster in the dgg record.
dgg.addCluster(drawingGroupId, 1);
}
else
{
// No:
// Find the cluster for this drawing group with free space.
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
{
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
if (c.getDrawingGroupId() == drawingGroupId)
{
if (c.getNumShapeIdsUsed() != 1024)
{
// Increment the number of shapes used for this cluster.
c.incrementShapeId();
}
}
// If the last shape id = -1 then we know to find a free block;
if (dg.getLastMSOSPID() == -1)
{
newShapeId = findFreeSPIDBlock();
}
else
{
// The new shape id to be the last shapeid of this cluster + 1
newShapeId = dg.getLastMSOSPID() + 1;
}
}
}
// Increment the total number of shapes used in the dgg.
dgg.setNumShapesSaved(dgg.getNumShapesSaved() + 1);
// Is the new shape id >= max shape id for dgg?
if (newShapeId >= dgg.getShapeIdMax())
{
// Yes:
// Set the max shape id = new shape id + 1
dgg.setShapeIdMax(newShapeId + 1);
}
// Set last shape id for this drawing group.
dg.setLastMSOSPID(newShapeId);
// Increased the number of shapes used for this drawing group.
dg.incrementShapeCount();
return newShapeId;
}
//////////// Non-public methods /////////////
short findNewDrawingGroupId()
{
short dgId = 1;
while ( drawingGroupExists( dgId ) )
dgId++;
return dgId;
}
boolean drawingGroupExists( short dgId )
{
for ( int i = 0; i < dgg.getFileIdClusters().length; i++ )
{
if ( dgg.getFileIdClusters()[i].getDrawingGroupId() == dgId )
return true;
}
return false;
}
int findFreeSPIDBlock()
{
int max = dgg.getShapeIdMax();
int next = ( ( max / 1024 ) + 1 ) * 1024;
return next;
}
public EscherDggRecord getDgg()
{
return dgg;
}
}

View File

@ -17,24 +17,23 @@
package org.apache.poi.hssf.model;
import java.util.ArrayList;
import java.util.List;
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
import java.util.List;
import java.util.ArrayList;
import org.apache.poi.util.Removal;
/**
* Provides utilities to manage drawing groups.
*/
public class DrawingManager2
{
EscherDggRecord dgg;
List<EscherDgRecord> drawingGroups = new ArrayList<EscherDgRecord>();
public class DrawingManager2 {
private final EscherDggRecord dgg;
private final List<EscherDgRecord> drawingGroups = new ArrayList<EscherDgRecord>();
public DrawingManager2( EscherDggRecord dgg )
{
public DrawingManager2( EscherDggRecord dgg ) {
this.dgg = dgg;
}
@ -50,8 +49,7 @@ public class DrawingManager2
*
* @return a new drawing group
*/
public EscherDgRecord createDgRecord()
{
public EscherDgRecord createDgRecord() {
EscherDgRecord dg = new EscherDgRecord();
dg.setRecordId( EscherDgRecord.RECORD_ID );
short dgId = findNewDrawingGroupId();
@ -70,11 +68,34 @@ public class DrawingManager2
* @param drawingGroupId the drawing group id
*
* @return a new shape id
*
* @deprecated in POI 3.17-beta2, use allocateShapeId(EscherDgRecord)
*/
public int allocateShapeId(short drawingGroupId)
{
EscherDgRecord dg = getDrawingGroup(drawingGroupId);
return allocateShapeId(drawingGroupId, dg);
@Deprecated
@Removal(version="4.0")
public int allocateShapeId(short drawingGroupId) {
for (EscherDgRecord dg : drawingGroups) {
if (dg.getDrawingGroupId() == drawingGroupId) {
return allocateShapeId(dg);
}
}
throw new IllegalStateException("Drawing group id "+drawingGroupId+" doesn't exist.");
}
/**
* Allocates new shape id for the drawing group
*
* @param drawingGroupId the drawing group id
* @param dg the EscherDgRecord which receives the new shape
*
* @return a new shape id.
*
* @deprecated in POI 3.17-beta2, use allocateShapeId(EscherDgRecord)
*/
@Deprecated
@Removal(version="4.0")
public int allocateShapeId(short drawingGroupId, EscherDgRecord dg) {
return allocateShapeId(dg);
}
/**
@ -85,71 +106,17 @@ public class DrawingManager2
*
* @return a new shape id.
*/
public int allocateShapeId(short drawingGroupId, EscherDgRecord dg)
{
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
// Add to existing cluster if space available
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
{
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
if (c.getDrawingGroupId() == drawingGroupId && c.getNumShapeIdsUsed() != 1024)
{
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
c.incrementShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 );
dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax())
dgg.setShapeIdMax( result + 1 );
return result;
}
}
// Create new cluster
dgg.addCluster( drawingGroupId, 0 );
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 );
int result = (1024 * dgg.getFileIdClusters().length);
dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax())
dgg.setShapeIdMax( result + 1 );
return result;
public int allocateShapeId(EscherDgRecord dg) {
return dgg.allocateShapeId(dg, true);
}
//////////// Non-public methods /////////////
/**
* Finds the next available (1 based) drawing group id
*
* @return the next available drawing group id
*/
public short findNewDrawingGroupId()
{
short dgId = 1;
while ( drawingGroupExists( dgId ) )
dgId++;
return dgId;
}
EscherDgRecord getDrawingGroup(int drawingGroupId)
{
return drawingGroups.get(drawingGroupId-1);
}
boolean drawingGroupExists( short dgId )
{
for ( int i = 0; i < dgg.getFileIdClusters().length; i++ )
{
if ( dgg.getFileIdClusters()[i].getDrawingGroupId() == dgId )
return true;
}
return false;
}
int findFreeSPIDBlock()
{
int max = dgg.getShapeIdMax();
int next = ( ( max / 1024 ) + 1 ) * 1024;
return next;
public short findNewDrawingGroupId() {
return dgg.findNewDrawingGroupId();
}
/**
@ -157,8 +124,7 @@ public class DrawingManager2
*
* @return the drawing group container record
*/
public EscherDggRecord getDgg()
{
public EscherDggRecord getDgg() {
return dgg;
}

View File

@ -2163,7 +2163,7 @@ public final class InternalWorkbook {
throw new RecordFormatException("EscherDgRecord wasn't set/processed before.");
}
EscherSpRecord sp = (EscherSpRecord)shapeChildRecord;
int shapeId = drawingManager.allocateShapeId((short)dgId, dg);
int shapeId = drawingManager.allocateShapeId(dg);
//allocateShapeId increments the number of shapes. roll back to the previous value
dg.setNumShapes(dg.getNumShapes()-1);
sp.setShapeId(shapeId);

View File

@ -429,8 +429,7 @@ public final class HSSFPatriarch implements HSSFShapeContainer, Drawing<HSSFShap
DrawingManager2 dm = _sheet.getWorkbook().getWorkbook().getDrawingManager();
EscherDgRecord dg =
_boundAggregate.getEscherContainer().getChildById(EscherDgRecord.RECORD_ID);
short drawingGroupId = dg.getDrawingGroupId();
return dm.allocateShapeId(drawingGroupId, dg);
return dm.allocateShapeId(dg);
}
/**

View File

@ -81,7 +81,6 @@ import org.apache.poi.util.Beta;
import org.apache.poi.util.Internal;
import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger;
import org.apache.poi.util.Removal;
import org.apache.poi.util.Units;
import org.apache.poi.xssf.model.CommentsTable;
import org.apache.poi.xssf.usermodel.XSSFPivotTable.PivotTableReferenceConfigurator;
@ -92,7 +91,51 @@ import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.*;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTAutoFilter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCalcPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCellFormula;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCommentList;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidation;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDataValidations;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHyperlink;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIgnoredError;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTIgnoredErrors;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTLegacyDrawing;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCell;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMergeCells;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObject;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOleObjects;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTOutlinePr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageBreak;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageMargins;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPageSetUpPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTPrintOptions;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTRow;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSelection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetCalcPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetFormatPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetProtection;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetView;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSheetViews;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTablePart;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableParts;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheetSource;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCalcMode;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPane;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STPaneState;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument;
/**
* High level representation of a SpreadsheetML worksheet.
@ -3265,20 +3308,6 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet {
return new CellAddress(address);
}
/**
* Sets location of the active cell
*
* @param cellRef the location of the active cell, e.g. <code>A1</code>..
* @deprecated 3.14beta2 (circa 2015-12-05). Use {@link #setActiveCell(CellAddress)} instead.
*/
@Deprecated
@Removal(version="3.16")
public void setActiveCell(String cellRef) {
CTSelection ctsel = getSheetTypeSelection();
ctsel.setActiveCell(cellRef);
ctsel.setSqref(Arrays.asList(cellRef));
}
/**
* {@inheritDoc}
*/

View File

@ -212,40 +212,10 @@ public abstract class HSLFSheet implements HSLFShapeContainer, Sheet<HSLFShape,H
*
* @return a new shape id.
*/
public int allocateShapeId()
{
public int allocateShapeId() {
EscherDggRecord dgg = _slideShow.getDocumentRecord().getPPDrawingGroup().getEscherDggRecord();
EscherDgRecord dg = _container.getPPDrawing().getEscherDgRecord();
dgg.setNumShapesSaved( dgg.getNumShapesSaved() + 1 );
// Add to existing cluster if space available
for (int i = 0; i < dgg.getFileIdClusters().length; i++)
{
EscherDggRecord.FileIdCluster c = dgg.getFileIdClusters()[i];
if (c.getDrawingGroupId() == dg.getDrawingGroupId() && c.getNumShapeIdsUsed() != 1024)
{
int result = c.getNumShapeIdsUsed() + (1024 * (i+1));
c.incrementShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 );
dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax()) {
dgg.setShapeIdMax( result + 1 );
}
return result;
}
}
// Create new cluster
dgg.addCluster( dg.getDrawingGroupId(), 0, false );
dgg.getFileIdClusters()[dgg.getFileIdClusters().length-1].incrementShapeId();
dg.setNumShapes( dg.getNumShapes() + 1 );
int result = (1024 * dgg.getFileIdClusters().length);
dg.setLastMSOSPID( result );
if (result >= dgg.getShapeIdMax()) {
dgg.setShapeIdMax( result + 1 );
}
return result;
return dgg.allocateShapeId(dg, false);
}
/**

View File

@ -166,7 +166,6 @@ public final class HSLFSlide extends HSLFSheet implements Slide<HSLFShape,HSLFTe
int dgId = dgg.getMaxDrawingGroupId() + 1;
dg.setOptions((short)(dgId << 4));
dgg.setDrawingsSaved(dgg.getDrawingsSaved() + 1);
dgg.setMaxDrawingGroupId(dgId);
for (EscherContainerRecord c : dgContainer.getChildContainers()) {
EscherSpRecord spr = null;

View File

@ -445,9 +445,9 @@ public final class TestShapes {
assertEquals(dgShapesUsed + 1, dg.getNumShapes());
//check that EscherDggRecord is updated
assertEquals(shape.getShapeId() + 1, dgg.getShapeIdMax());
assertEquals(dggMaxId + 1, dgg.getShapeIdMax());
assertEquals(dggShapesUsed + 1, dgg.getNumShapesSaved());
assertEquals("mismatch @"+i, shape.getShapeId() + 1, dgg.getShapeIdMax());
assertEquals("mismatch @"+i, dggMaxId + 1, dgg.getShapeIdMax());
assertEquals("mismatch @"+i, dggShapesUsed + 1, dgg.getNumShapesSaved());
dggShapesUsed = dgg.getNumShapesSaved();
dggMaxId = dgg.getShapeIdMax();

View File

@ -25,9 +25,8 @@ import org.junit.runners.Suite;
*/
@RunWith(Suite.class)
@Suite.SuiteClasses({
TestDrawingManager.class,
TestDrawingManager2.class,
//TestFormulaParser.class, //converted to junit4
TestFormulaParser.class,
TestFormulaParserEval.class,
TestFormulaParserIf.class,
TestLinkTable.class,

View File

@ -1,95 +0,0 @@
/* ====================================================================
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.model;
import junit.framework.TestCase;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherDgRecord;
/**
* @deprecated in POI 3.15-beta2, scheduled for removal in 3.17, use DrawingManager2 instead
*/
@Deprecated
public final class TestDrawingManager extends TestCase {
public void testFindFreeSPIDBlock() {
EscherDggRecord dgg = new EscherDggRecord();
DrawingManager dm = new DrawingManager( dgg );
dgg.setShapeIdMax( 1024 );
assertEquals( 2048, dm.findFreeSPIDBlock() );
dgg.setShapeIdMax( 1025 );
assertEquals( 2048, dm.findFreeSPIDBlock() );
dgg.setShapeIdMax( 2047 );
assertEquals( 2048, dm.findFreeSPIDBlock() );
}
public void testFindNewDrawingGroupId() {
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 1 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
new EscherDggRecord.FileIdCluster( 2, 10 )} );
DrawingManager dm = new DrawingManager( dgg );
assertEquals( 1, dm.findNewDrawingGroupId() );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
new EscherDggRecord.FileIdCluster( 1, 10 ),
new EscherDggRecord.FileIdCluster( 2, 10 )} );
assertEquals( 3, dm.findNewDrawingGroupId() );
}
public void testDrawingGroupExists() {
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 1 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
new EscherDggRecord.FileIdCluster( 2, 10 )} );
DrawingManager dm = new DrawingManager( dgg );
assertFalse( dm.drawingGroupExists( (short) 1 ) );
assertTrue( dm.drawingGroupExists( (short) 2 ) );
assertFalse( dm.drawingGroupExists( (short) 3 ) );
}
public void testCreateDgRecord() {
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 0 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{} );
DrawingManager dm = new DrawingManager( dgg );
EscherDgRecord dgRecord = dm.createDgRecord();
assertEquals( -1, dgRecord.getLastMSOSPID() );
assertEquals( 0, dgRecord.getNumShapes() );
assertEquals( 1, dm.getDgg().getDrawingsSaved() );
assertEquals( 1, dm.getDgg().getFileIdClusters().length );
assertEquals( 1, dm.getDgg().getFileIdClusters()[0].getDrawingGroupId() );
assertEquals( 0, dm.getDgg().getFileIdClusters()[0].getNumShapeIdsUsed() );
}
public void testAllocateShapeId() {
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 0 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{} );
DrawingManager dm = new DrawingManager( dgg );
EscherDgRecord dg = dm.createDgRecord();
int shapeId = dm.allocateShapeId( dg.getDrawingGroupId() );
assertEquals( 1024, shapeId );
assertEquals( 1025, dgg.getShapeIdMax() );
assertEquals( 1, dgg.getDrawingsSaved() );
assertEquals( 1, dgg.getFileIdClusters()[0].getDrawingGroupId() );
assertEquals( 1, dgg.getFileIdClusters()[0].getNumShapeIdsUsed() );
assertEquals( 1024, dg.getLastMSOSPID() );
assertEquals( 1, dg.getNumShapes() );
}
}

View File

@ -17,21 +17,25 @@
package org.apache.poi.hssf.model;
import junit.framework.TestCase;
import org.apache.poi.ddf.EscherDggRecord;
import org.apache.poi.ddf.EscherDgRecord;
import static org.junit.Assert.assertEquals;
public final class TestDrawingManager2 extends TestCase {
import org.apache.poi.ddf.EscherDgRecord;
import org.apache.poi.ddf.EscherDggRecord;
import org.junit.Before;
import org.junit.Test;
public final class TestDrawingManager2 {
private DrawingManager2 drawingManager2;
private EscherDggRecord dgg;
@Override
protected void setUp() {
@Before
public void setUp() {
dgg = new EscherDggRecord();
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[0] );
drawingManager2 = new DrawingManager2( dgg );
}
@Test
public void testCreateDgRecord() {
EscherDgRecord dgRecord1 = drawingManager2.createDgRecord();
assertEquals( 1, dgRecord1.getDrawingGroupId() );
@ -47,33 +51,71 @@ public final class TestDrawingManager2 extends TestCase {
assertEquals( 0, dgg.getNumShapesSaved() );
}
@Test
public void testCreateDgRecordOld() {
// converted from TestDrawingManager(1)
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 0 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{} );
DrawingManager2 dm = new DrawingManager2( dgg );
EscherDgRecord dgRecord = dm.createDgRecord();
assertEquals( -1, dgRecord.getLastMSOSPID() );
assertEquals( 0, dgRecord.getNumShapes() );
assertEquals( 1, dm.getDgg().getDrawingsSaved() );
assertEquals( 1, dm.getDgg().getFileIdClusters().length );
assertEquals( 1, dm.getDgg().getFileIdClusters()[0].getDrawingGroupId() );
assertEquals( 0, dm.getDgg().getFileIdClusters()[0].getNumShapeIdsUsed() );
}
@Test
public void testAllocateShapeId() {
EscherDgRecord dgRecord1 = drawingManager2.createDgRecord();
assertEquals( 1, dgg.getDrawingsSaved() );
EscherDgRecord dgRecord2 = drawingManager2.createDgRecord();
assertEquals( 2, dgg.getDrawingsSaved() );
assertEquals( 1024, drawingManager2.allocateShapeId( (short)1 ) );
assertEquals( 1024, drawingManager2.allocateShapeId( dgRecord1 ) );
assertEquals( 1024, dgRecord1.getLastMSOSPID() );
assertEquals( 1025, dgg.getShapeIdMax() );
assertEquals( 1025, drawingManager2.allocateShapeId( (short)1 ) );
assertEquals( 1, dgg.getFileIdClusters()[0].getDrawingGroupId() );
assertEquals( 1, dgg.getFileIdClusters()[0].getNumShapeIdsUsed() );
assertEquals( 1, dgRecord1.getNumShapes() );
assertEquals( 1025, drawingManager2.allocateShapeId( dgRecord1 ) );
assertEquals( 1025, dgRecord1.getLastMSOSPID() );
assertEquals( 1026, dgg.getShapeIdMax() );
assertEquals( 1026, drawingManager2.allocateShapeId( (short)1 ) );
assertEquals( 1026, drawingManager2.allocateShapeId( dgRecord1 ) );
assertEquals( 1026, dgRecord1.getLastMSOSPID() );
assertEquals( 1027, dgg.getShapeIdMax() );
assertEquals( 2048, drawingManager2.allocateShapeId( (short)2 ) );
assertEquals( 2048, drawingManager2.allocateShapeId( dgRecord2 ) );
assertEquals( 2048, dgRecord2.getLastMSOSPID() );
assertEquals( 2049, dgg.getShapeIdMax() );
for (int i = 0; i < 1021; i++)
{
drawingManager2.allocateShapeId( (short)1 );
drawingManager2.allocateShapeId( dgRecord1 );
assertEquals( 2049, dgg.getShapeIdMax() );
}
assertEquals( 3072, drawingManager2.allocateShapeId( (short) 1 ) );
assertEquals( 3072, drawingManager2.allocateShapeId( dgRecord1 ) );
assertEquals( 3073, dgg.getShapeIdMax() );
assertEquals( 2, dgg.getDrawingsSaved() );
assertEquals( 4, dgg.getNumIdClusters() );
assertEquals( 1026, dgg.getNumShapesSaved() );
}
@Test
public void testFindNewDrawingGroupId() {
// converted from TestDrawingManager(1)
EscherDggRecord dgg = new EscherDggRecord();
dgg.setDrawingsSaved( 1 );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
new EscherDggRecord.FileIdCluster( 2, 10 )} );
DrawingManager2 dm = new DrawingManager2( dgg );
assertEquals( 1, dm.findNewDrawingGroupId() );
dgg.setFileIdClusters( new EscherDggRecord.FileIdCluster[]{
new EscherDggRecord.FileIdCluster( 1, 10 ),
new EscherDggRecord.FileIdCluster( 2, 10 )} );
assertEquals( 3, dm.findNewDrawingGroupId() );
}
}

View File

@ -42,6 +42,11 @@ public class HSSFTestHelper {
return 1025; //Mock value
}
@Override
public int allocateShapeId(EscherDgRecord dg) {
return 1025;
}
@Override
public int allocateShapeId(short drawingGroupId, EscherDgRecord dg) {
return 1025;

View File

@ -874,19 +874,18 @@ public final class TestHSSFSheet extends BaseTestSheet {
HSSFSheet sheet1 = wb1.getSheetAt(0);
wb1.getWorkbook().findDrawingGroup();
DrawingManager2 dm1 = wb1.getWorkbook().getDrawingManager();
DrawingManager2 dm1 = wb1.getWorkbook().findDrawingGroup();
int maxDrawingGroupId1 = dm1.getDgg().getMaxDrawingGroupId();
wb1.cloneSheet(0);
//check EscherDggRecord - a workbook-level registry of drawing objects
assertEquals(maxDrawingGroupId1 + 1, dm1.getDgg().getMaxDrawingGroupId());
HSSFWorkbook wb2 = HSSFTestDataSamples.writeOutAndReadBack(wb1);
wb1.close();
wb2.getWorkbook().findDrawingGroup();
DrawingManager2 dm2 = wb2.getWorkbook().getDrawingManager();
//check EscherDggRecord - a workbook-level registry of drawing objects
assertEquals(dm1.getDgg().getMaxDrawingGroupId() + 1, dm2.getDgg().getMaxDrawingGroupId());
DrawingManager2 dm2 = wb2.getWorkbook().findDrawingGroup();
assertEquals(maxDrawingGroupId1 + 1, dm2.getDgg().getMaxDrawingGroupId());
HSSFSheet sheet2 = wb2.getSheetAt(1);