324 lines
11 KiB
Java
324 lines
11 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.model;
|
||
|
||
import org.apache.poi.ddf.*;
|
||
import org.apache.poi.hslf.model.ShapeTypes;
|
||
import org.apache.poi.hslf.record.ColorSchemeAtom;
|
||
import org.apache.poi.util.POILogger;
|
||
import org.apache.poi.util.POILogFactory;
|
||
|
||
import java.util.Iterator;
|
||
import java.awt.*;
|
||
|
||
/**
|
||
* <p>
|
||
* Represents a Shape which is the elemental object that composes a drawing.
|
||
* This class is a wrapper around EscherSpContainer which holds all information
|
||
* about a shape in PowerPoint document.
|
||
* </p>
|
||
* <p>
|
||
* When you add a shape, you usually specify the dimensions of the shape and the position
|
||
* of the upper<65>left corner of the bounding box for the shape relative to the upper<65>left
|
||
* corner of the page, worksheet, or slide. Distances in the drawing layer are measured
|
||
* in points (72 points = 1 inch).
|
||
* </p>
|
||
* <p>
|
||
*
|
||
* @author Yegor Kozlov
|
||
*/
|
||
public abstract class Shape {
|
||
|
||
// For logging
|
||
protected POILogger logger = POILogFactory.getLogger(this.getClass());
|
||
|
||
/**
|
||
* In Escher absolute distances are specified in
|
||
* English Metric Units (EMUs), occasionally referred to as A units;
|
||
* there are 360000 EMUs per centimeter, 914400 EMUs per inch, 12700 EMUs per point.
|
||
*/
|
||
public static final int EMU_PER_INCH = 914400;
|
||
public static final int EMU_PER_POINT = 12700;
|
||
public static final int EMU_PER_CENTIMETER = 360000;
|
||
|
||
/**
|
||
* Master DPI (576 pixels per inch).
|
||
* Used by the reference coordinate system in PowerPoint.
|
||
*/
|
||
public static final int MASTER_DPI = 576;
|
||
|
||
/**
|
||
* Pixels DPI (96 pixels per inch)
|
||
*/
|
||
public static final int PIXEL_DPI = 96;
|
||
|
||
/**
|
||
* Points DPI (72 pixels per inch)
|
||
*/
|
||
public static final int POINT_DPI = 72;
|
||
|
||
/**
|
||
* Either EscherSpContainer or EscheSpgrContainer record
|
||
* which holds information about this shape.
|
||
*/
|
||
protected EscherContainerRecord _escherContainer;
|
||
|
||
/**
|
||
* Parent of this shape.
|
||
* <code>null</code> for the topmost shapes.
|
||
*/
|
||
protected Shape _parent;
|
||
|
||
/**
|
||
* The <code>Sheet</code> this shape belongs to
|
||
*/
|
||
protected Sheet _sheet;
|
||
|
||
/**
|
||
* Create a Shape object. This constructor is used when an existing Shape is read from from a PowerPoint document.
|
||
*
|
||
* @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
|
||
* @param parent the parent of this Shape
|
||
*/
|
||
protected Shape(EscherContainerRecord escherRecord, Shape parent){
|
||
_escherContainer = escherRecord;
|
||
_parent = parent;
|
||
}
|
||
|
||
/**
|
||
* Creates the lowerlevel escher records for this shape.
|
||
*/
|
||
protected abstract EscherContainerRecord createSpContainer(boolean isChild);
|
||
|
||
/**
|
||
* @return the parent of this shape
|
||
*/
|
||
public Shape getParent(){
|
||
return _parent;
|
||
}
|
||
|
||
/**
|
||
* @return name of the shape.
|
||
*/
|
||
public String getShapeName(){
|
||
return ShapeTypes.typeName(getShapeType());
|
||
}
|
||
|
||
/**
|
||
* @return type of the shape.
|
||
* @see org.apache.poi.hslf.record.RecordTypes
|
||
*/
|
||
public int getShapeType(){
|
||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||
return spRecord.getOptions() >> 4;
|
||
}
|
||
|
||
/**
|
||
* @param type type of the shape.
|
||
* @see org.apache.poi.hslf.record.RecordTypes
|
||
*/
|
||
public void setShapeType(int type){
|
||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||
spRecord.setOptions((short)(type << 4 | 0x2));
|
||
}
|
||
|
||
/**
|
||
* Returns the anchor (the bounding box rectangle) of this shape.
|
||
* All coordinates are expressed in points (72 dpi).
|
||
*
|
||
* @return the anchor of this shape
|
||
*/
|
||
public java.awt.Rectangle getAnchor(){
|
||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||
int flags = spRecord.getFlags();
|
||
java.awt.Rectangle anchor=null;
|
||
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
|
||
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
|
||
anchor = new java.awt.Rectangle();
|
||
anchor.x = rec.getDx1()*POINT_DPI/MASTER_DPI;
|
||
anchor.y = rec.getDy1()*POINT_DPI/MASTER_DPI;
|
||
anchor.width = rec.getDx2()*POINT_DPI/MASTER_DPI - anchor.x;
|
||
anchor.height = rec.getDy2()*POINT_DPI/MASTER_DPI - anchor.y;
|
||
}
|
||
else {
|
||
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
|
||
anchor = new java.awt.Rectangle();
|
||
anchor.y = rec.getFlag()*POINT_DPI/MASTER_DPI;
|
||
anchor.x = rec.getCol1()*POINT_DPI/MASTER_DPI;
|
||
anchor.width = (rec.getDx1() - rec.getCol1())*POINT_DPI/MASTER_DPI;
|
||
anchor.height = (rec.getRow1() - rec.getFlag())*POINT_DPI/MASTER_DPI;
|
||
}
|
||
return anchor;
|
||
}
|
||
|
||
/**
|
||
* Sets the anchor (the bounding box rectangle) of this shape.
|
||
* All coordinates should be expressed in points (72 dpi).
|
||
*
|
||
* @param anchor new anchor
|
||
*/
|
||
public void setAnchor(java.awt.Rectangle anchor){
|
||
EscherSpRecord spRecord = _escherContainer.getChildById(EscherSpRecord.RECORD_ID);
|
||
int flags = spRecord.getFlags();
|
||
if ((flags & EscherSpRecord.FLAG_CHILD) != 0){
|
||
EscherChildAnchorRecord rec = (EscherChildAnchorRecord)getEscherChild(_escherContainer, EscherChildAnchorRecord.RECORD_ID);
|
||
rec.setDx1(anchor.x*MASTER_DPI/POINT_DPI);
|
||
rec.setDy1(anchor.y*MASTER_DPI/POINT_DPI);
|
||
rec.setDx2((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI);
|
||
rec.setDy2((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI);
|
||
}
|
||
else {
|
||
EscherClientAnchorRecord rec = (EscherClientAnchorRecord)getEscherChild(_escherContainer, EscherClientAnchorRecord.RECORD_ID);
|
||
rec.setFlag((short)(anchor.y*MASTER_DPI/POINT_DPI));
|
||
rec.setCol1((short)(anchor.x*MASTER_DPI/POINT_DPI));
|
||
rec.setDx1((short)((anchor.width + anchor.x)*MASTER_DPI/POINT_DPI));
|
||
rec.setRow1((short)((anchor.height + anchor.y)*MASTER_DPI/POINT_DPI));
|
||
}
|
||
|
||
}
|
||
|
||
/**
|
||
* Moves the top left corner of the shape to the specified point.
|
||
*
|
||
* @param x the x coordinate of the top left corner of the shape
|
||
* @param y the y coordinate of the top left corner of the shape
|
||
*/
|
||
public void moveTo(int x, int y){
|
||
java.awt.Rectangle anchor = getAnchor();
|
||
anchor.setLocation(x, y);
|
||
setAnchor(anchor);
|
||
}
|
||
|
||
/**
|
||
* Helper method to return escher child by record ID
|
||
*
|
||
* @return escher record or <code>null</code> if not found.
|
||
*/
|
||
public static EscherRecord getEscherChild(EscherContainerRecord owner, int recordId){
|
||
for ( Iterator iterator = owner.getChildRecords().iterator(); iterator.hasNext(); )
|
||
{
|
||
EscherRecord escherRecord = (EscherRecord) iterator.next();
|
||
if (escherRecord.getRecordId() == recordId)
|
||
return escherRecord;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Returns escher property by id.
|
||
*
|
||
* @return escher property or <code>null</code> if not found.
|
||
*/
|
||
public static EscherProperty getEscherProperty(EscherOptRecord opt, int propId){
|
||
for ( Iterator iterator = opt.getEscherProperties().iterator(); iterator.hasNext(); )
|
||
{
|
||
EscherProperty prop = (EscherProperty) iterator.next();
|
||
if (prop.getPropertyNumber() == propId)
|
||
return prop;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Set an escher property for this shape.
|
||
*
|
||
* @param opt The opt record to set the properties to.
|
||
* @param propId The id of the property. One of the constants defined in EscherOptRecord.
|
||
* @param value value of the property. If value = -1 then the property is removed.
|
||
*/
|
||
public static void setEscherProperty(EscherOptRecord opt, short propId, int value){
|
||
java.util.List props = opt.getEscherProperties();
|
||
for ( Iterator iterator = props.iterator(); iterator.hasNext(); ) {
|
||
EscherProperty prop = (EscherProperty) iterator.next();
|
||
if (prop.getId() == propId){
|
||
iterator.remove();
|
||
}
|
||
}
|
||
if (value != -1) {
|
||
opt.addEscherProperty(new EscherSimpleProperty(propId, value));
|
||
opt.sortProperties();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @return The shape container and it's children that can represent this
|
||
* shape.
|
||
*/
|
||
public EscherContainerRecord getSpContainer(){
|
||
return _escherContainer;
|
||
}
|
||
|
||
/**
|
||
* Event which fires when a shape is inserted in the sheet.
|
||
* In some cases we need to propagate changes to upper level containers.
|
||
* <br>
|
||
* Default implementation does nothing.
|
||
*
|
||
* @param sh - owning shape
|
||
*/
|
||
protected void afterInsert(Sheet sh){
|
||
|
||
}
|
||
|
||
/**
|
||
* @return the <code>SlideShow</code> this shape belongs to
|
||
*/
|
||
public Sheet getSheet(){
|
||
return _sheet;
|
||
}
|
||
|
||
/**
|
||
* Assign the <code>SlideShow</code> this shape belongs to
|
||
*
|
||
* @param sheet owner of this shape
|
||
*/
|
||
public void setSheet(Sheet sheet){
|
||
_sheet = sheet;
|
||
}
|
||
|
||
protected Color getColor(int rgb){
|
||
if (rgb >= 0x8000000) {
|
||
int idx = rgb - 0x8000000;
|
||
ColorSchemeAtom ca = getSheet().getColorScheme();
|
||
if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx);
|
||
}
|
||
Color tmp = new Color(rgb, true);
|
||
return new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed());
|
||
}
|
||
|
||
/**
|
||
* Fill properties of this shape
|
||
*
|
||
* @return fill properties of this shape
|
||
*/
|
||
public Fill getFill(){
|
||
return new Fill(this);
|
||
}
|
||
|
||
|
||
/**
|
||
* Returns the hyperlink assigned to this shape
|
||
*
|
||
* @return the hyperlink assigned to this shape
|
||
* or <code>null</code> if not found.
|
||
*/
|
||
public Hyperlink getHyperlink(){
|
||
return Hyperlink.find(this);
|
||
}
|
||
|
||
}
|