001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017: package org.apache.poi.hslf.model;
018:
019: import org.apache.poi.ddf.*;
020: import org.apache.poi.util.LittleEndian;
021: import org.apache.poi.util.POILogger;
022:
023: import java.util.ArrayList;
024: import java.util.List;
025:
026: /**
027: * Represents a group of shapes.
028: *
029: * @author Yegor Kozlov
030: */
031: public class ShapeGroup extends Shape {
032:
033: /**
034: * Create a new ShapeGroup. This constructor is used when a new shape is created.
035: *
036: */
037: public ShapeGroup() {
038: this (null, null);
039: _escherContainer = createSpContainer(false);
040: }
041:
042: /**
043: * Create a ShapeGroup object and initilize it from the supplied Record container.
044: *
045: * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
046: * @param parent the parent of the shape
047: */
048: protected ShapeGroup(EscherContainerRecord escherRecord,
049: Shape parent) {
050: super (escherRecord, parent);
051: }
052:
053: /**
054: * @return the shapes contained in this group container
055: */
056: public Shape[] getShapes() {
057: // Out escher container record should contain serveral
058: // SpContainers, the first of which is the group shape itself
059: List lst = _escherContainer.getChildRecords();
060:
061: ArrayList shapeList = new ArrayList();
062: // Don't include the first SpContainer, it is always NotPrimitive
063: for (int i = 1; i < lst.size(); i++) {
064: EscherRecord r = (EscherRecord) lst.get(i);
065: if (r instanceof EscherContainerRecord) {
066: // Create the Shape for it
067: EscherContainerRecord container = (EscherContainerRecord) r;
068: Shape shape = ShapeFactory.createShape(container, this );
069: shape.setSheet(getSheet());
070: shapeList.add(shape);
071: } else {
072: // Should we do anything special with these non
073: // Container records?
074: logger.log(POILogger.ERROR,
075: "Shape contained non container escher record, was "
076: + r.getClass().getName());
077: }
078: }
079:
080: // Put the shapes into an array, and return
081: Shape[] shapes = (Shape[]) shapeList
082: .toArray(new Shape[shapeList.size()]);
083: return shapes;
084: }
085:
086: /**
087: * Sets the anchor (the bounding box rectangle) of this shape.
088: * All coordinates should be expressed in Master units (576 dpi).
089: *
090: * @param anchor new anchor
091: */
092: public void setAnchor(java.awt.Rectangle anchor) {
093:
094: EscherContainerRecord spContainer = (EscherContainerRecord) _escherContainer
095: .getChildRecords().get(0);
096:
097: EscherClientAnchorRecord clientAnchor = (EscherClientAnchorRecord) getEscherChild(
098: spContainer, EscherClientAnchorRecord.RECORD_ID);
099: //hack. internal variable EscherClientAnchorRecord.shortRecord can be
100: //initialized only in fillFields(). We need to set shortRecord=false;
101: byte[] header = new byte[16];
102: LittleEndian.putUShort(header, 0, 0);
103: LittleEndian.putUShort(header, 2, 0);
104: LittleEndian.putInt(header, 4, 8);
105: clientAnchor.fillFields(header, 0, null);
106:
107: clientAnchor
108: .setFlag((short) (anchor.y * MASTER_DPI / POINT_DPI));
109: clientAnchor
110: .setCol1((short) (anchor.x * MASTER_DPI / POINT_DPI));
111: clientAnchor.setDx1((short) ((anchor.width + anchor.x)
112: * MASTER_DPI / POINT_DPI));
113: clientAnchor.setRow1((short) ((anchor.height + anchor.y)
114: * MASTER_DPI / POINT_DPI));
115:
116: EscherSpgrRecord spgr = (EscherSpgrRecord) getEscherChild(
117: spContainer, EscherSpgrRecord.RECORD_ID);
118:
119: spgr.setRectX1(anchor.x * MASTER_DPI / POINT_DPI);
120: spgr.setRectY1(anchor.y * MASTER_DPI / POINT_DPI);
121: spgr.setRectX2((anchor.x + anchor.width) * MASTER_DPI
122: / POINT_DPI);
123: spgr.setRectY2((anchor.y + anchor.height) * MASTER_DPI
124: / POINT_DPI);
125: }
126:
127: /**
128: * Create a new ShapeGroup and create an instance of <code>EscherSpgrContainer</code> which represents a group of shapes
129: */
130: protected EscherContainerRecord createSpContainer(boolean isChild) {
131: EscherContainerRecord spgr = new EscherContainerRecord();
132: spgr.setRecordId(EscherContainerRecord.SPGR_CONTAINER);
133: spgr.setOptions((short) 15);
134:
135: //The group itself is a shape, and always appears as the first EscherSpContainer in the group container.
136: EscherContainerRecord spcont = new EscherContainerRecord();
137: spcont.setRecordId(EscherContainerRecord.SP_CONTAINER);
138: spcont.setOptions((short) 15);
139:
140: EscherSpgrRecord spg = new EscherSpgrRecord();
141: spg.setOptions((short) 1);
142: spcont.addChildRecord(spg);
143:
144: EscherSpRecord sp = new EscherSpRecord();
145: short type = (ShapeTypes.NotPrimitive << 4) + 2;
146: sp.setOptions(type);
147: sp.setFlags(EscherSpRecord.FLAG_HAVEANCHOR
148: | EscherSpRecord.FLAG_GROUP);
149: spcont.addChildRecord(sp);
150:
151: EscherClientAnchorRecord anchor = new EscherClientAnchorRecord();
152: spcont.addChildRecord(anchor);
153:
154: spgr.addChildRecord(spcont);
155: return spgr;
156: }
157:
158: /**
159: * Add a shape to this group.
160: *
161: * @param shape - the Shape to add
162: */
163: public void addShape(Shape shape) {
164: _escherContainer.addChildRecord(shape.getSpContainer());
165:
166: Sheet sheet = getSheet();
167: shape.setSheet(sheet);
168: shape.afterInsert(sheet);
169:
170: if (shape instanceof TextBox) {
171: TextBox tbox = (TextBox) shape;
172: getSheet().getPPDrawing().addTextboxWrapper(tbox._txtbox);
173: }
174: }
175:
176: /**
177: * Moves this <code>ShapeGroup</code> to the specified location.
178: * <p>
179: * @param x the x coordinate of the top left corner of the shape in new location
180: * @param y the y coordinate of the top left corner of the shape in new location
181: */
182: public void moveTo(int x, int y) {
183: java.awt.Rectangle anchor = getAnchor();
184: int dx = x - anchor.x;
185: int dy = y - anchor.y;
186: anchor.translate(dx, dy);
187: setAnchor(anchor);
188:
189: Shape[] shape = getShapes();
190: for (int i = 0; i < shape.length; i++) {
191: java.awt.Rectangle chanchor = shape[i].getAnchor();
192: chanchor.translate(dx, dy);
193: shape[i].setAnchor(chanchor);
194: }
195: }
196:
197: /**
198: * Returns the anchor (the bounding box rectangle) of this shape group.
199: * All coordinates are expressed in points (72 dpi).
200: *
201: * @return the anchor of this shape group
202: */
203: public java.awt.Rectangle getAnchor() {
204: EscherContainerRecord groupInfoContainer = (EscherContainerRecord) _escherContainer
205: .getChild(0);
206: EscherSpgrRecord spgr = (EscherSpgrRecord) getEscherChild(
207: groupInfoContainer, EscherSpgrRecord.RECORD_ID);
208: java.awt.Rectangle anchor = null;
209:
210: anchor = new java.awt.Rectangle();
211: anchor.x = spgr.getRectX1() * POINT_DPI / MASTER_DPI;
212: anchor.y = spgr.getRectY1() * POINT_DPI / MASTER_DPI;
213: anchor.width = (spgr.getRectX2() - spgr.getRectX1())
214: * POINT_DPI / MASTER_DPI;
215: anchor.height = (spgr.getRectY2() - spgr.getRectY1())
216: * POINT_DPI / MASTER_DPI;
217: return anchor;
218: }
219:
220: /**
221: * Return type of the shape.
222: * In most cases shape group type is {@link org.apache.poi.hslf.model.ShapeTypes#NotPrimitive}
223: *
224: * @return type of the shape.
225: */
226: public int getShapeType() {
227: EscherContainerRecord groupInfoContainer = (EscherContainerRecord) _escherContainer
228: .getChild(0);
229: EscherSpRecord spRecord = groupInfoContainer
230: .getChildById(EscherSpRecord.RECORD_ID);
231: return spRecord.getOptions() >> 4;
232: }
233:
234: /**
235: * Returns <code>null</code> - shape groups can't have hyperlinks
236: *
237: * @return <code>null</code>.
238: */
239: public Hyperlink getHyperlink() {
240: return null;
241: }
242:
243: }
|