399 lines
12 KiB
Java
399 lines
12 KiB
Java
/* ====================================================================
|
|
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.hslf.usermodel;
|
|
|
|
import java.awt.Graphics2D;
|
|
import java.util.*;
|
|
|
|
import org.apache.poi.ddf.*;
|
|
import org.apache.poi.hslf.record.*;
|
|
import org.apache.poi.sl.draw.DrawFactory;
|
|
import org.apache.poi.sl.draw.Drawable;
|
|
import org.apache.poi.sl.usermodel.Sheet;
|
|
import org.apache.poi.util.POILogFactory;
|
|
import org.apache.poi.util.POILogger;
|
|
|
|
/**
|
|
* This class defines the common format of "Sheets" in a powerpoint
|
|
* document. Such sheets could be Slides, Notes, Master etc
|
|
*
|
|
* @author Nick Burch
|
|
* @author Yegor Kozlov
|
|
*/
|
|
|
|
public abstract class HSLFSheet implements Sheet<HSLFShape,HSLFSlideShow> {
|
|
private static POILogger logger = POILogFactory.getLogger(HSLFSheet.class);
|
|
|
|
/**
|
|
* The <code>SlideShow</code> we belong to
|
|
*/
|
|
private HSLFSlideShow _slideShow;
|
|
|
|
/**
|
|
* Sheet background
|
|
*/
|
|
private HSLFBackground _background;
|
|
|
|
/**
|
|
* Record container that holds sheet data.
|
|
* For slides it is org.apache.poi.hslf.record.Slide,
|
|
* for notes it is org.apache.poi.hslf.record.Notes,
|
|
* for slide masters it is org.apache.poi.hslf.record.SlideMaster, etc.
|
|
*/
|
|
private SheetContainer _container;
|
|
|
|
private int _sheetNo;
|
|
|
|
public HSLFSheet(SheetContainer container, int sheetNo) {
|
|
_container = container;
|
|
_sheetNo = sheetNo;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all the TextRuns in the sheet.
|
|
*/
|
|
public abstract List<List<HSLFTextParagraph>> getTextParagraphs();
|
|
|
|
/**
|
|
* Returns the (internal, RefID based) sheet number, as used
|
|
* to in PersistPtr stuff.
|
|
*/
|
|
public int _getSheetRefId() {
|
|
return _container.getSheetId();
|
|
}
|
|
|
|
/**
|
|
* Returns the (internal, SlideIdentifier based) sheet number, as used
|
|
* to reference this sheet from other records.
|
|
*/
|
|
public int _getSheetNumber() {
|
|
return _sheetNo;
|
|
}
|
|
|
|
/**
|
|
* Fetch the PPDrawing from the underlying record
|
|
*/
|
|
public PPDrawing getPPDrawing() {
|
|
return _container.getPPDrawing();
|
|
}
|
|
|
|
/**
|
|
* Fetch the SlideShow we're attached to
|
|
*/
|
|
public HSLFSlideShow getSlideShow() {
|
|
return _slideShow;
|
|
}
|
|
|
|
/**
|
|
* Return record container for this sheet
|
|
*/
|
|
public SheetContainer getSheetContainer() {
|
|
return _container;
|
|
}
|
|
|
|
/**
|
|
* Set the SlideShow we're attached to.
|
|
* Also passes it on to our child RichTextRuns
|
|
*/
|
|
public void setSlideShow(HSLFSlideShow ss) {
|
|
_slideShow = ss;
|
|
List<List<HSLFTextParagraph>> trs = getTextParagraphs();
|
|
if (trs == null) return;
|
|
for (List<HSLFTextParagraph> ltp : trs) {
|
|
for (HSLFTextParagraph tp : ltp) {
|
|
tp.supplySheet(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Returns all shapes contained in this Sheet
|
|
*
|
|
* @return all shapes contained in this Sheet (Slide or Notes)
|
|
*/
|
|
@Override
|
|
public List<HSLFShape> getShapes() {
|
|
PPDrawing ppdrawing = getPPDrawing();
|
|
|
|
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
|
EscherContainerRecord spgr = null;
|
|
|
|
for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
|
|
EscherRecord rec = it.next();
|
|
if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
|
|
spgr = (EscherContainerRecord) rec;
|
|
break;
|
|
}
|
|
}
|
|
if (spgr == null) {
|
|
throw new IllegalStateException("spgr not found");
|
|
}
|
|
|
|
List<HSLFShape> shapeList = new ArrayList<HSLFShape>();
|
|
Iterator<EscherRecord> it = spgr.getChildIterator();
|
|
if (it.hasNext()) {
|
|
// skip first item
|
|
it.next();
|
|
}
|
|
for (; it.hasNext();) {
|
|
EscherContainerRecord sp = (EscherContainerRecord) it.next();
|
|
HSLFShape sh = HSLFShapeFactory.createShape(sp, null);
|
|
sh.setSheet(this);
|
|
shapeList.add(sh);
|
|
}
|
|
|
|
return shapeList;
|
|
}
|
|
|
|
/**
|
|
* Add a new Shape to this Slide
|
|
*
|
|
* @param shape - the Shape to add
|
|
*/
|
|
public void addShape(HSLFShape shape) {
|
|
PPDrawing ppdrawing = getPPDrawing();
|
|
|
|
EscherContainerRecord dgContainer = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
|
EscherContainerRecord spgr = (EscherContainerRecord) HSLFShape.getEscherChild(dgContainer, EscherContainerRecord.SPGR_CONTAINER);
|
|
spgr.addChildRecord(shape.getSpContainer());
|
|
|
|
shape.setSheet(this);
|
|
shape.setShapeId(allocateShapeId());
|
|
shape.afterInsert(this);
|
|
}
|
|
|
|
/**
|
|
* Allocates new shape id for the new drawing group id.
|
|
*
|
|
* @return a new shape id.
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Removes the specified shape from this sheet.
|
|
*
|
|
* @param shape shape to be removed from this sheet, if present.
|
|
* @return <tt>true</tt> if the shape was deleted.
|
|
*/
|
|
public boolean removeShape(HSLFShape shape) {
|
|
PPDrawing ppdrawing = getPPDrawing();
|
|
|
|
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
|
EscherContainerRecord spgr = null;
|
|
|
|
for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
|
|
EscherRecord rec = it.next();
|
|
if (rec.getRecordId() == EscherContainerRecord.SPGR_CONTAINER) {
|
|
spgr = (EscherContainerRecord) rec;
|
|
break;
|
|
}
|
|
}
|
|
if(spgr == null) {
|
|
return false;
|
|
}
|
|
|
|
List<EscherRecord> lst = spgr.getChildRecords();
|
|
boolean result = lst.remove(shape.getSpContainer());
|
|
spgr.setChildRecords(lst);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Called by SlideShow ater a new sheet is created
|
|
*/
|
|
public void onCreate(){
|
|
|
|
}
|
|
|
|
/**
|
|
* Return the master sheet .
|
|
*/
|
|
public abstract HSLFMasterSheet getMasterSheet();
|
|
|
|
/**
|
|
* Color scheme for this sheet.
|
|
*/
|
|
public ColorSchemeAtom getColorScheme() {
|
|
return _container.getColorScheme();
|
|
}
|
|
|
|
/**
|
|
* Returns the background shape for this sheet.
|
|
*
|
|
* @return the background shape for this sheet.
|
|
*/
|
|
public HSLFBackground getBackground() {
|
|
if (_background == null) {
|
|
PPDrawing ppdrawing = getPPDrawing();
|
|
|
|
EscherContainerRecord dg = (EscherContainerRecord) ppdrawing.getEscherRecords()[0];
|
|
EscherContainerRecord spContainer = null;
|
|
|
|
for (Iterator<EscherRecord> it = dg.getChildIterator(); it.hasNext();) {
|
|
EscherRecord rec = it.next();
|
|
if (rec.getRecordId() == EscherContainerRecord.SP_CONTAINER) {
|
|
spContainer = (EscherContainerRecord) rec;
|
|
break;
|
|
}
|
|
}
|
|
_background = new HSLFBackground(spContainer, null);
|
|
_background.setSheet(this);
|
|
}
|
|
return _background;
|
|
}
|
|
|
|
@Override
|
|
public void draw(Graphics2D graphics) {
|
|
DrawFactory drawFact = DrawFactory.getInstance(graphics);
|
|
Drawable draw = drawFact.getDrawable(this);
|
|
draw.draw(graphics);
|
|
}
|
|
|
|
/**
|
|
* Subclasses should call this method and update the array of text runs
|
|
* when a text shape is added
|
|
*
|
|
* @param shape
|
|
*/
|
|
protected void onAddTextShape(HSLFTextShape shape) {
|
|
}
|
|
|
|
/**
|
|
* Return placeholder by text type
|
|
*
|
|
* @param type type of text, See {@link org.apache.poi.hslf.record.TextHeaderAtom}
|
|
* @return <code>TextShape</code> or <code>null</code>
|
|
*/
|
|
public HSLFTextShape getPlaceholderByTextType(int type){
|
|
for (HSLFShape shape : getShapes()) {
|
|
if(shape instanceof HSLFTextShape){
|
|
HSLFTextShape tx = (HSLFTextShape)shape;
|
|
if (tx != null && tx.getRunType() == type) {
|
|
return tx;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Search text placeholer by its type
|
|
*
|
|
* @param type type of placeholder to search. See {@link org.apache.poi.hslf.record.OEPlaceholderAtom}
|
|
* @return <code>TextShape</code> or <code>null</code>
|
|
*/
|
|
public HSLFTextShape getPlaceholder(int type){
|
|
for (HSLFShape shape : getShapes()) {
|
|
if(shape instanceof HSLFTextShape){
|
|
HSLFTextShape tx = (HSLFTextShape)shape;
|
|
int placeholderId = 0;
|
|
OEPlaceholderAtom oep = tx.getPlaceholderAtom();
|
|
if(oep != null) {
|
|
placeholderId = oep.getPlaceholderId();
|
|
} else {
|
|
//special case for files saved in Office 2007
|
|
RoundTripHFPlaceholder12 hldr = tx.getClientDataRecord(RecordTypes.RoundTripHFPlaceholder12.typeID);
|
|
if(hldr != null) placeholderId = hldr.getPlaceholderId();
|
|
}
|
|
if(placeholderId == type){
|
|
return tx;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Return programmable tag associated with this sheet, e.g. <code>___PPT12</code>.
|
|
*
|
|
* @return programmable tag associated with this sheet.
|
|
*/
|
|
public String getProgrammableTag(){
|
|
String tag = null;
|
|
RecordContainer progTags = (RecordContainer)
|
|
getSheetContainer().findFirstOfType(
|
|
RecordTypes.ProgTags.typeID
|
|
);
|
|
if(progTags != null) {
|
|
RecordContainer progBinaryTag = (RecordContainer)
|
|
progTags.findFirstOfType(
|
|
RecordTypes.ProgBinaryTag.typeID
|
|
);
|
|
if(progBinaryTag != null) {
|
|
CString binaryTag = (CString)
|
|
progBinaryTag.findFirstOfType(
|
|
RecordTypes.CString.typeID
|
|
);
|
|
if(binaryTag != null) tag = binaryTag.getText();
|
|
}
|
|
}
|
|
|
|
return tag;
|
|
|
|
}
|
|
|
|
public Iterator<HSLFShape> iterator() {
|
|
return getShapes().iterator();
|
|
}
|
|
|
|
|
|
/**
|
|
* @return whether shapes on the master sheet should be shown. By default master graphics is turned off.
|
|
* Sheets that support the notion of master (slide, slideLayout) should override it and
|
|
* check this setting
|
|
*/
|
|
public boolean getFollowMasterGraphics() {
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|