]> source.dussan.org Git - poi.git/commitdiff
User model for drawing format support
authorGlen Stampoultzis <glens@apache.org>
Tue, 10 Feb 2004 22:00:27 +0000 (22:00 +0000)
committerGlen Stampoultzis <glens@apache.org>
Tue, 10 Feb 2004 22:00:27 +0000 (22:00 +0000)
git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/branches/REL_2_BRANCH@353497 13f79535-47bb-0310-9956-ffa450edef68

20 files changed:
src/java/org/apache/poi/hssf/usermodel/DummyGraphics2d.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/FontDetails.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFFont.java
src/java/org/apache/poi/hssf/usermodel/HSSFPalette.java
src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFShape.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java
src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java [new file with mode: 0644]

diff --git a/src/java/org/apache/poi/hssf/usermodel/DummyGraphics2d.java b/src/java/org/apache/poi/hssf/usermodel/DummyGraphics2d.java
new file mode 100644 (file)
index 0000000..44b8e4d
--- /dev/null
@@ -0,0 +1,773 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.awt.*;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.awt.font.GlyphVector;
+import java.awt.font.FontRenderContext;
+import java.util.Map;
+import java.text.AttributedCharacterIterator;
+
+public class DummyGraphics2d
+        extends Graphics2D
+{
+    BufferedImage img;
+    private Graphics2D g2D;
+
+    public DummyGraphics2d()
+    {
+        img = new BufferedImage(1000, 1000, 2);
+        g2D = (Graphics2D)img.getGraphics();
+    }
+
+    public void addRenderingHints(Map hints)
+    {
+        System.out.println( "addRenderingHinds(Map):" );
+        System.out.println( "  hints = " + hints );
+        g2D.addRenderingHints( hints );
+    }
+
+    public void clip(Shape s)
+    {
+        System.out.println( "clip(Shape):" );
+        System.out.println( "  s = " + s );
+        g2D.clip( s );
+    }
+
+    public void draw(Shape s)
+    {
+        System.out.println( "draw(Shape):" );
+        System.out.println( "s = " + s );
+        g2D.draw( s );
+    }
+
+    public void drawGlyphVector(GlyphVector g, float x, float y)
+    {
+        System.out.println( "drawGlyphVector(GlyphVector, float, float):" );
+        System.out.println( "g = " + g );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawGlyphVector( g, x, y );
+    }
+
+    public void drawImage(BufferedImage img,
+                                  BufferedImageOp op,
+                                  int x,
+                                  int y)
+    {
+        System.out.println( "drawImage(BufferedImage, BufferedImageOp, x, y):" );
+        System.out.println( "img = " + img );
+        System.out.println( "op = " + op );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawImage( img, op, x, y );
+    }
+
+    public boolean drawImage(Image img,
+                                      AffineTransform xform,
+                                      ImageObserver obs)
+    {
+        System.out.println( "drawImage(Image,AfflineTransform,ImageObserver):" );
+        System.out.println( "img = " + img );
+        System.out.println( "xform = " + xform );
+        System.out.println( "obs = " + obs );
+        return g2D.drawImage( img, xform, obs );
+    }
+
+    public void drawRenderableImage(RenderableImage img,
+                                             AffineTransform xform)
+    {
+        System.out.println( "drawRenderableImage(RenderableImage, AfflineTransform):" );
+        System.out.println( "img = " + img );
+        System.out.println( "xform = " + xform );
+        g2D.drawRenderableImage( img, xform );
+    }
+
+    public void drawRenderedImage(RenderedImage img,
+                                           AffineTransform xform)
+    {
+        System.out.println( "drawRenderedImage(RenderedImage, AffineTransform):" );
+        System.out.println( "img = " + img );
+        System.out.println( "xform = " + xform );
+        g2D.drawRenderedImage( img, xform );
+    }
+
+    public void drawString(AttributedCharacterIterator iterator,
+                                    float x, float y)
+    {
+        System.out.println( "drawString(AttributedCharacterIterator):" );
+        System.out.println( "iterator = " + iterator );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawString( iterator, x, y );
+    }
+
+//    public void drawString(AttributedCharacterIterator iterator,
+//                                    int x, int y)
+//    {
+//        g2D.drawString( iterator, x, y );
+//    }
+
+    public void drawString(String s, float x, float y)
+    {
+        System.out.println( "drawString(s,x,y):" );
+        System.out.println( "s = " + s );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawString( s, x, y );
+    }
+
+//    public void drawString(String str, int x, int y)
+//    {
+//        g2D.drawString( str, x, y );
+//    }
+
+    public void fill(Shape s)
+    {
+        System.out.println( "fill(Shape):" );
+        System.out.println( "s = " + s );
+        g2D.fill( s );
+    }
+
+//    public void fill3DRect(int x, int y, int width, int height,
+//                        boolean raised) {
+//        g2D.fill3DRect( x, y, width, height, raised );
+//    }
+
+    public Color getBackground()
+    {
+        System.out.println( "getBackground():" );
+        return g2D.getBackground();
+    }
+
+    public Composite getComposite()
+    {
+        System.out.println( "getComposite():" );
+        return g2D.getComposite();
+    }
+
+    public GraphicsConfiguration getDeviceConfiguration()
+    {
+        System.out.println( "getDeviceConfiguration():" );
+        return g2D.getDeviceConfiguration();
+    }
+
+    public FontRenderContext getFontRenderContext()
+    {
+        System.out.println( "getFontRenderContext():" );
+        return g2D.getFontRenderContext();
+    }
+
+    public Paint getPaint()
+    {
+        System.out.println( "getPaint():" );
+        return g2D.getPaint();
+    }
+
+    public Object getRenderingHint(RenderingHints.Key hintKey)
+    {
+        System.out.println( "getRenderingHint(RenderingHints.Key):" );
+        System.out.println( "hintKey = " + hintKey );
+        return g2D.getRenderingHint( hintKey );
+    }
+
+    public RenderingHints getRenderingHints()
+    {
+        System.out.println( "getRenderingHints():" );
+        return g2D.getRenderingHints();
+    }
+
+    public Stroke getStroke()
+    {
+        System.out.println( "getStroke():" );
+        return g2D.getStroke();
+    }
+
+    public AffineTransform getTransform()
+    {
+        System.out.println( "getTransform():" );
+        return g2D.getTransform();
+    }
+
+    public boolean hit(Rectangle rect,
+                               Shape s,
+                               boolean onStroke)
+    {
+        System.out.println( "hit(Rectangle, Shape, onStroke):" );
+        System.out.println( "rect = " + rect );
+        System.out.println( "s = " + s );
+        System.out.println( "onStroke = " + onStroke );
+        return g2D.hit( rect, s, onStroke );
+    }
+
+    public void rotate(double theta)
+    {
+        System.out.println( "rotate(theta):" );
+        System.out.println( "theta = " + theta );
+        g2D.rotate( theta );
+    }
+
+    public void rotate(double theta, double x, double y)
+    {
+        System.out.println( "rotate(double,double,double):" );
+        System.out.println( "theta = " + theta );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.rotate( theta, x, y );
+    }
+
+    public void scale(double sx, double sy)
+    {
+        System.out.println( "scale(double,double):" );
+        System.out.println( "sx = " + sx );
+        System.out.println( "sy" );
+        g2D.scale( sx, sy );
+    }
+
+    public void setBackground(Color color)
+    {
+        System.out.println( "setBackground(Color):" );
+        System.out.println( "color = " + color );
+        g2D.setBackground( color );
+    }
+
+    public void setComposite(Composite comp)
+    {
+        System.out.println( "setComposite(Composite):" );
+        System.out.println( "comp = " + comp );
+        g2D.setComposite( comp );
+    }
+
+    public void setPaint( Paint paint )
+    {
+        System.out.println( "setPain(Paint):" );
+        System.out.println( "paint = " + paint );
+        g2D.setPaint( paint );
+    }
+
+    public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue)
+    {
+        System.out.println( "setRenderingHint(RenderingHints.Key, Object):" );
+        System.out.println( "hintKey = " + hintKey );
+        System.out.println( "hintValue = " + hintValue );
+        g2D.setRenderingHint( hintKey, hintValue );
+    }
+
+    public void setRenderingHints(Map hints)
+    {
+        System.out.println( "setRenderingHints(Map):" );
+        System.out.println( "hints = " + hints );
+        g2D.setRenderingHints( hints );
+    }
+
+    public void setStroke(Stroke s)
+    {
+        System.out.println( "setStroke(Stoke):" );
+        System.out.println( "s = " + s );
+        g2D.setStroke( s );
+    }
+
+    public void setTransform(AffineTransform Tx)
+    {
+        System.out.println( "setTransform():" );
+        System.out.println( "Tx = " + Tx );
+        g2D.setTransform( Tx );
+    }
+
+    public void shear(double shx, double shy)
+    {
+        System.out.println( "shear(shx, dhy):" );
+        System.out.println( "shx = " + shx );
+        System.out.println( "shy = " + shy );
+        g2D.shear( shx, shy );
+    }
+
+    public void transform(AffineTransform Tx)
+    {
+        System.out.println( "transform(AffineTransform):" );
+        System.out.println( "Tx = " + Tx );
+        g2D.transform( Tx );
+    }
+
+    public void translate(double tx, double ty)
+    {
+        System.out.println( "translate(double, double):" );
+        System.out.println( "tx = " + tx );
+        System.out.println( "ty = " + ty );
+        g2D.translate( tx, ty );
+    }
+
+//    public void translate(int x, int y)
+//    {
+//        g2D.translate( x, y );
+//    }
+
+    public void clearRect(int x, int y, int width, int height)
+    {
+        System.out.println( "clearRect(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.clearRect( x, y, width, height );
+    }
+
+    public void clipRect(int x, int y, int width, int height)
+    {
+        System.out.println( "clipRect(int, int, int, int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.clipRect( x, y, width, height );
+    }
+
+    public void copyArea(int x, int y, int width, int height,
+                                 int dx, int dy)
+    {
+        System.out.println( "copyArea(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.copyArea( x, y, width, height, dx, dy );
+    }
+
+    public Graphics create()
+    {
+        System.out.println( "create():" );
+        return g2D.create();
+    }
+
+    public Graphics create(int x, int y, int width, int height) {
+        System.out.println( "create(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        return g2D.create( x, y, width, height );
+    }
+
+    public void dispose()
+    {
+        System.out.println( "dispose():" );
+        g2D.dispose();
+    }
+
+    public void draw3DRect(int x, int y, int width, int height,
+                          boolean raised) {
+        System.out.println( "draw3DRect(int,int,int,int,boolean):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "raised = " + raised );
+        g2D.draw3DRect( x, y, width, height, raised );
+    }
+
+    public void drawArc(int x, int y, int width, int height,
+                                int startAngle, int arcAngle)
+    {
+        System.out.println( "drawArc(int,int,int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "startAngle = " + startAngle );
+        System.out.println( "arcAngle = " + arcAngle );
+        g2D.drawArc( x, y, width, height, startAngle, arcAngle );
+    }
+
+    public void drawBytes(byte data[], int offset, int length, int x, int y) {
+        System.out.println( "drawBytes(byte[],int,int,int,int):" );
+        System.out.println( "data = " + data );
+        System.out.println( "offset = " + offset );
+        System.out.println( "length = " + length );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawBytes( data, offset, length, x, y );
+    }
+
+    public void drawChars(char data[], int offset, int length, int x, int y) {
+        System.out.println( "drawChars(data,int,int,int,int):" );
+        System.out.println( "data = " + data );
+        System.out.println( "offset = " + offset );
+        System.out.println( "length = " + length );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawChars( data, offset, length, x, y );
+    }
+
+    public boolean drawImage(Image img,
+                                     int dx1, int dy1, int dx2, int dy2,
+                                     int sx1, int sy1, int sx2, int sy2,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,int,int,int,int,int,int,ImageObserver):" );
+        System.out.println( "img = " + img );
+        System.out.println( "dx1 = " + dx1 );
+        System.out.println( "dy1 = " + dy1 );
+        System.out.println( "dx2 = " + dx2 );
+        System.out.println( "dy2 = " + dy2 );
+        System.out.println( "sx1 = " + sx1 );
+        System.out.println( "sy1 = " + sy1 );
+        System.out.println( "sx2 = " + sx2 );
+        System.out.println( "sy2 = " + sy2 );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer );
+    }
+
+    public boolean drawImage(Image img,
+                                     int dx1, int dy1, int dx2, int dy2,
+                                     int sx1, int sy1, int sx2, int sy2,
+                                     Color bgcolor,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,int,int,int,int,int,int,Color,ImageObserver):" );
+        System.out.println( "img = " + img );
+        System.out.println( "dx1 = " + dx1 );
+        System.out.println( "dy1 = " + dy1 );
+        System.out.println( "dx2 = " + dx2 );
+        System.out.println( "dy2 = " + dy2 );
+        System.out.println( "sx1 = " + sx1 );
+        System.out.println( "sy1 = " + sy1 );
+        System.out.println( "sx2 = " + sx2 );
+        System.out.println( "sy2 = " + sy2 );
+        System.out.println( "bgcolor = " + bgcolor );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor, observer );
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                                     Color bgcolor,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,Color,ImageObserver):" );
+        System.out.println( "img = " + img );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "bgcolor = " + bgcolor );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, x, y, bgcolor, observer );
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,observer):" );
+        System.out.println( "img = " + img );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, x, y, observer );
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                                     int width, int height,
+                                     Color bgcolor,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,int,int,Color,ImageObserver):" );
+        System.out.println( "img = " + img );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "bgcolor = " + bgcolor );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, x, y, width, height, bgcolor, observer );
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                                     int width, int height,
+                                     ImageObserver observer)
+    {
+        System.out.println( "drawImage(Image,int,int,width,height,observer):" );
+        System.out.println( "img = " + img );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "observer = " + observer );
+        return g2D.drawImage( img, x, y, width, height, observer );
+    }
+
+    public void drawLine(int x1, int y1, int x2, int y2)
+    {
+        System.out.println( "drawLine(int,int,int,int):" );
+        System.out.println( "x1 = " + x1 );
+        System.out.println( "y1 = " + y1 );
+        System.out.println( "x2 = " + x2 );
+        System.out.println( "y2 = " + y2 );
+        g2D.drawLine( x1, y1, x2, y2 );
+    }
+
+    public void drawOval(int x, int y, int width, int height)
+    {
+        System.out.println( "drawOval(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.drawOval( x, y, width, height );
+    }
+
+    public void drawPolygon(Polygon p) {
+        System.out.println( "drawPolygon(Polygon):" );
+        System.out.println( "p = " + p );
+        g2D.drawPolygon( p );
+    }
+
+    public void drawPolygon(int xPoints[], int yPoints[],
+                                    int nPoints)
+    {
+        System.out.println( "drawPolygon(int[],int[],int):" );
+        System.out.println( "xPoints = " + xPoints );
+        System.out.println( "yPoints = " + yPoints );
+        System.out.println( "nPoints = " + nPoints );
+        g2D.drawPolygon( xPoints, yPoints, nPoints );
+    }
+
+    public void drawPolyline(int xPoints[], int yPoints[],
+                                     int nPoints)
+    {
+        System.out.println( "drawPolyline(int[],int[],int):" );
+        System.out.println( "xPoints = " + xPoints );
+        System.out.println( "yPoints = " + yPoints );
+        System.out.println( "nPoints = " + nPoints );
+        g2D.drawPolyline( xPoints, yPoints, nPoints );
+    }
+
+    public void drawRect(int x, int y, int width, int height) {
+        System.out.println( "drawRect(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.drawRect( x, y, width, height );
+    }
+
+    public void drawRoundRect(int x, int y, int width, int height,
+                                      int arcWidth, int arcHeight)
+    {
+        System.out.println( "drawRoundRect(int,int,int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "arcWidth = " + arcWidth );
+        System.out.println( "arcHeight = " + arcHeight );
+        g2D.drawRoundRect( x, y, width, height, arcWidth, arcHeight );
+    }
+
+    public void drawString(AttributedCharacterIterator iterator,
+                                    int x, int y)
+    {
+        System.out.println( "drawString(AttributedCharacterIterator,int,int):" );
+        System.out.println( "iterator = " + iterator );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawString( iterator, x, y );
+    }
+
+    public void drawString(String str, int x, int y)
+    {
+        System.out.println( "drawString(str,int,int):" );
+        System.out.println( "str = " + str );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.drawString( str, x, y );
+    }
+
+    public void fill3DRect(int x, int y, int width, int height,
+                          boolean raised) {
+        System.out.println( "fill3DRect(int,int,int,int,boolean):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "raised = " + raised );
+        g2D.fill3DRect( x, y, width, height, raised );
+    }
+
+    public void fillArc(int x, int y, int width, int height,
+                                int startAngle, int arcAngle)
+    {
+        System.out.println( "fillArc(int,int,int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        System.out.println( "startAngle = " + startAngle );
+        System.out.println( "arcAngle = " + arcAngle );
+        g2D.fillArc( x, y, width, height, startAngle, arcAngle );
+    }
+
+    public void fillOval(int x, int y, int width, int height)
+    {
+        System.out.println( "fillOval(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.fillOval( x, y, width, height );
+    }
+
+    public void fillPolygon(Polygon p) {
+        System.out.println( "fillPolygon(Polygon):" );
+        System.out.println( "p = " + p );
+        g2D.fillPolygon( p );
+    }
+
+    public void fillPolygon(int xPoints[], int yPoints[],
+                                    int nPoints)
+    {
+        System.out.println( "fillPolygon(int[],int[],int):" );
+        System.out.println( "xPoints = " + xPoints );
+        System.out.println( "yPoints = " + yPoints );
+        System.out.println( "nPoints = " + nPoints );
+        g2D.fillPolygon( xPoints, yPoints, nPoints );
+    }
+
+    public void fillRect(int x, int y, int width, int height)
+    {
+        System.out.println( "fillRect(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.fillRect( x, y, width, height );
+    }
+
+    public void fillRoundRect(int x, int y, int width, int height,
+                                      int arcWidth, int arcHeight)
+    {
+        System.out.println( "fillRoundRect(int,int,int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.fillRoundRect( x, y, width, height, arcWidth, arcHeight );
+    }
+
+    public void finalize() {
+        System.out.println( "finalize():" );
+        g2D.finalize();
+    }
+
+    public Shape getClip()
+    {
+        System.out.println( "getClip():" );
+        return g2D.getClip();
+    }
+
+    public Rectangle getClipBounds()
+    {
+        System.out.println( "getClipBounds():" );
+        return g2D.getClipBounds();
+    }
+
+    public Rectangle getClipBounds(Rectangle r) {
+        System.out.println( "getClipBounds(Rectangle):" );
+        System.out.println( "r = " + r );
+        return g2D.getClipBounds( r );
+    }
+
+    public Rectangle getClipRect() {
+        System.out.println( "getClipRect():" );
+        return g2D.getClipRect();
+    }
+
+    public Color getColor()
+    {
+        System.out.println( "getColor():" );
+        return g2D.getColor();
+    }
+
+    public Font getFont()
+    {
+        System.out.println( "getFont():" );
+        return g2D.getFont();
+    }
+
+    public FontMetrics getFontMetrics() {
+        System.out.println( "getFontMetrics():" );
+        return g2D.getFontMetrics();
+    }
+
+    public FontMetrics getFontMetrics(Font f)
+    {
+        System.out.println( "getFontMetrics():" );
+        return g2D.getFontMetrics( f );
+    }
+
+    public boolean hitClip(int x, int y, int width, int height) {
+        System.out.println( "hitClip(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        return g2D.hitClip( x, y, width, height );
+    }
+
+    public void setClip(Shape clip)
+    {
+        System.out.println( "setClip(Shape):" );
+        System.out.println( "clip = " + clip );
+        g2D.setClip( clip );
+    }
+
+    public void setClip(int x, int y, int width, int height)
+    {
+        System.out.println( "setClip(int,int,int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        System.out.println( "width = " + width );
+        System.out.println( "height = " + height );
+        g2D.setClip( x, y, width, height );
+    }
+
+    public void setColor(Color c)
+    {
+        System.out.println( "setColor():" );
+        System.out.println( "c = " + c );
+        g2D.setColor( c );
+    }
+
+    public void setFont(Font font)
+    {
+        System.out.println( "setFont(Font):" );
+        System.out.println( "font = " + font );
+        g2D.setFont( font );
+    }
+
+    public void setPaintMode()
+    {
+        System.out.println( "setPaintMode():" );
+        g2D.setPaintMode();
+    }
+
+    public void setXORMode(Color c1)
+    {
+        System.out.println( "setXORMode(Color):" );
+        System.out.println( "c1 = " + c1 );
+        g2D.setXORMode( c1 );
+    }
+
+    public String toString() {
+        System.out.println( "toString():" );
+        return g2D.toString();
+    }
+
+    public void translate(int x, int y)
+    {
+        System.out.println( "translate(int,int):" );
+        System.out.println( "x = " + x );
+        System.out.println( "y = " + y );
+        g2D.translate( x, y );
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics.java
new file mode 100644 (file)
index 0000000..fa8065a
--- /dev/null
@@ -0,0 +1,450 @@
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+import org.apache.poi.hssf.util.HSSFColor;
+
+import java.awt.*;
+import java.awt.image.ImageObserver;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * Translates Graphics calls into escher calls.  The translation is lossy so
+ * many features are not supported and some just aren't implemented yet.  If
+ * in doubt test the specific calls you wish to make. Graphics calls are
+ * always performed into an EscherGroup so one will need to be created.
+ * <p>
+ * <b>Important:</b>
+ * <blockquote>
+ * One important concept worth considering is that of font size.  One of the
+ * difficulties in converting Graphics calls into escher drawing calls is that
+ * Excel does not have the concept of absolute pixel positions.  It measures
+ * it's cell widths in 'characters' and the cell heights in points.
+ * Unfortunately it's not defined exactly what a type of character it's
+ * measuring.  Presumably this is due to the fact that the Excel will be
+ * using different fonts on different platforms or even within the same
+ * platform.
+ * <p>
+ * Because of this constraint we've had to calculate the
+ * verticalPointsPerPixel.  This the amount the font should be scaled by when
+ * you issue commands such as drawString().  A good way to calculate this
+ * is to use the follow formula:
+ * <p>
+ * <pre>
+ *      multipler = groupHeightInPoints / heightOfGroup
+ * </pre>
+ * <p>
+ * The height of the group is calculated fairly simply by calculating the
+ * difference between the y coordinates of the bounding box of the shape.  The
+ * height of the group can be calculated by using a convenience called
+ * <code>HSSFClientAnchor.getAnchorHeightInPoints()</code>.
+ * </blockquote>
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class EscherGraphics
+        extends Graphics
+{
+    private HSSFShapeGroup escherGroup;
+    private HSSFWorkbook workbook;
+    private float verticalPointsPerPixel = 1.0f;
+    private float verticalPixelsPerPoint;
+    private Color foreground;
+    private Color background = Color.white;
+    private Font font;
+    private static POILogger logger = POILogFactory.getLogger(EscherGraphics.class);
+
+    /**
+     * Construct an escher graphics object.
+     *
+     * @param escherGroup           The escher group to write the graphics calls into.
+     * @param workbook              The workbook we are using.
+     * @param forecolor             The foreground color to use as default.
+     * @param verticalPointsPerPixel    The font multiplier.  (See class description for information on how this works.).
+     */
+    public EscherGraphics(HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color forecolor, float verticalPointsPerPixel )
+    {
+        this.escherGroup = escherGroup;
+        this.workbook = workbook;
+        this.verticalPointsPerPixel = verticalPointsPerPixel;
+        this.verticalPixelsPerPoint = 1 / verticalPointsPerPixel;
+        this.font = new Font("Arial", 0, 10);
+        this.foreground = forecolor;
+//        background = backcolor;
+    }
+
+    /**
+     * Constructs an escher graphics object.
+     *
+     * @param escherGroup           The escher group to write the graphics calls into.
+     * @param workbook              The workbook we are using.
+     * @param foreground            The foreground color to use as default.
+     * @param verticalPointsPerPixel    The font multiplier.  (See class description for information on how this works.).
+     * @param font                  The font to use.
+     */
+    EscherGraphics( HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color foreground, Font font, float verticalPointsPerPixel )
+    {
+        this.escherGroup = escherGroup;
+        this.workbook = workbook;
+        this.foreground = foreground;
+//        this.background = background;
+        this.font = font;
+        this.verticalPointsPerPixel = verticalPointsPerPixel;
+        this.verticalPixelsPerPoint = 1 / verticalPointsPerPixel;
+    }
+
+    /**
+     * Constructs an escher graphics object.
+     *
+     * @param escherGroup           The escher group to write the graphics calls into.
+     * @param workbook              The workbook we are using.
+     * @param forecolor             The default foreground color.
+     */
+//    public EscherGraphics( HSSFShapeGroup escherGroup, HSSFWorkbook workbook, Color forecolor)
+//    {
+//        this(escherGroup, workbook, forecolor, 1.0f);
+//    }
+
+
+    public void clearRect(int x, int y, int width, int height)
+    {
+        Color color = foreground;
+        setColor(background);
+        fillRect(x,y,width,height);
+        setColor(color);
+    }
+
+    public void clipRect(int x, int y, int width, int height)
+    {
+        logger.log(POILogger.WARN,"clipRect not supported");
+    }
+
+    public void copyArea(int x, int y, int width, int height, int dx, int dy)
+    {
+        logger.log(POILogger.WARN,"copyArea not supported");
+    }
+
+    public Graphics create()
+    {
+        EscherGraphics g = new EscherGraphics(escherGroup, workbook,
+                foreground, font, verticalPointsPerPixel );
+        return g;
+    }
+
+    public void dispose()
+    {
+    }
+
+    public void drawArc(int x, int y, int width, int height,
+                                int startAngle, int arcAngle)
+    {
+        logger.log(POILogger.WARN,"drawArc not supported");
+    }
+
+    public boolean drawImage(Image img,
+                                     int dx1, int dy1, int dx2, int dy2,
+                                     int sx1, int sy1, int sx2, int sy2,
+                                     Color bgcolor,
+                                     ImageObserver observer)
+    {
+        logger.log(POILogger.WARN,"drawImage not supported");
+
+        return true;
+    }
+
+    public boolean drawImage(Image img,
+                                     int dx1, int dy1, int dx2, int dy2,
+                                     int sx1, int sy1, int sx2, int sy2,
+                                     ImageObserver observer)
+    {
+        logger.log(POILogger.WARN,"drawImage not supported");
+        return true;
+    }
+
+    public boolean drawImage(Image image, int i, int j, int k, int l, Color color, ImageObserver imageobserver)
+    {
+        return drawImage(image, i, j, i + k, j + l, 0, 0, image.getWidth(imageobserver), image.getHeight(imageobserver), color, imageobserver);
+    }
+
+    public boolean drawImage(Image image, int i, int j, int k, int l, ImageObserver imageobserver)
+    {
+        return drawImage(image, i, j, i + k, j + l, 0, 0, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
+    }
+
+    public boolean drawImage(Image image, int i, int j, Color color, ImageObserver imageobserver)
+    {
+        return drawImage(image, i, j, image.getWidth(imageobserver), image.getHeight(imageobserver), color, imageobserver);
+    }
+
+    public boolean drawImage(Image image, int i, int j, ImageObserver imageobserver)
+    {
+        return drawImage(image, i, j, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
+    }
+
+    public void drawLine(int x1, int y1, int x2, int y2)
+    {
+        HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor(x1, y1, x2, y2) );
+        shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_LINE);
+        shape.setLineWidth(0);
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+    }
+
+    public void drawOval(int x, int y, int width, int height)
+    {
+        HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor(x,y,x+width,y+height) );
+        shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
+        shape.setLineWidth(0);
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+        shape.setNoFill(true);
+    }
+
+    public void drawPolygon(int xPoints[], int yPoints[],
+                                    int nPoints)
+    {
+        int right  = findBiggest(xPoints);
+        int bottom = findBiggest(yPoints);
+        int left   = findSmallest(xPoints);
+        int top    = findSmallest(yPoints);
+        HSSFPolygon shape = escherGroup.createPolygon(new HSSFChildAnchor(left,top,right,bottom) );
+        shape.setPolygonDrawArea(right - left, bottom - top);
+        shape.setPoints(addToAll(xPoints, -left), addToAll(yPoints, -top));
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+        shape.setLineWidth(0);
+        shape.setNoFill(true);
+    }
+
+    private int[] addToAll( int[] values, int amount )
+    {
+        int[] result = new int[values.length];
+        for ( int i = 0; i < values.length; i++ )
+            result[i] = values[i] + amount;
+        return result;
+    }
+
+    public void drawPolyline(int xPoints[], int yPoints[],
+                                     int nPoints)
+    {
+        logger.log(POILogger.WARN,"drawPolyline not supported");
+    }
+
+    public void drawRect(int x, int y, int width, int height)
+    {
+        logger.log(POILogger.WARN,"drawRect not supported");
+    }
+
+    public void drawRoundRect(int x, int y, int width, int height,
+                                      int arcWidth, int arcHeight)
+    {
+        logger.log(POILogger.WARN,"drawRoundRect not supported");
+    }
+
+    public void drawString(String str, int x, int y)
+    {
+        if (str == null || str.equals(""))
+            return;
+
+        Font excelFont = font;
+        if ( font.getName().equals( "SansSerif" ) )
+        {
+            excelFont = new Font( "Arial", font.getStyle(), (int) ( font.getSize() / verticalPixelsPerPoint ) );
+        }
+        else
+        {
+            excelFont = new Font( font.getName(), font.getStyle(), (int) ( font.getSize() / verticalPixelsPerPoint ));
+        }
+        FontDetails d = StaticFontMetrics.getFontDetails( excelFont );
+        int width = (int) ( (d.getStringWidth( str ) * 2.5)  + 12 );
+        int height = (int) ( ( font.getSize() * 2.0 * verticalPixelsPerPoint ) + 6 );
+        y -= ( font.getSize() * verticalPixelsPerPoint );    // we want to draw the shape from the top-left
+        HSSFTextbox textbox = escherGroup.createTextbox( new HSSFChildAnchor( x, y, x + width, y + height ) );
+        textbox.setNoFill( true );
+        textbox.setLineStyle( HSSFShape.LINESTYLE_NONE );
+        HSSFRichTextString s = new HSSFRichTextString( str );
+        HSSFFont hssfFont = matchFont( excelFont );
+        s.applyFont( hssfFont );
+        textbox.setString( s );
+    }
+
+    private HSSFFont matchFont( Font font )
+    {
+        HSSFColor hssfColor = workbook.getCustomPalette()
+                .findColor((byte)foreground.getRed(), (byte)foreground.getGreen(), (byte)foreground.getBlue());
+        if (hssfColor == null)
+            hssfColor = workbook.getCustomPalette().findSimilarColor((byte)foreground.getRed(), (byte)foreground.getGreen(), (byte)foreground.getBlue());
+        boolean bold = (font.getStyle() & Font.BOLD) != 0;
+        boolean italic = (font.getStyle() & Font.ITALIC) != 0;
+        HSSFFont hssfFont = workbook.findFont(bold ? HSSFFont.BOLDWEIGHT_BOLD : 0,
+                    hssfColor.getIndex(),
+                    (short)(font.getSize() * 20),
+                    font.getName(),
+                    italic,
+                    false,
+                    (short)0,
+                    (byte)0);
+        if (hssfFont == null)
+        {
+            hssfFont = workbook.createFont();
+            hssfFont.setBoldweight(bold ? HSSFFont.BOLDWEIGHT_BOLD : 0);
+            hssfFont.setColor(hssfColor.getIndex());
+            hssfFont.setFontHeight((short)(font.getSize() * 20));
+            hssfFont.setFontName(font.getName());
+            hssfFont.setItalic(italic);
+            hssfFont.setStrikeout(false);
+            hssfFont.setTypeOffset((short) 0);
+            hssfFont.setUnderline((byte) 0);
+        }
+
+        return hssfFont;
+    }
+
+
+    public void drawString(AttributedCharacterIterator iterator,
+                                    int x, int y)
+    {
+        logger.log(POILogger.WARN,"drawString not supported");
+    }
+
+    public void fillArc(int x, int y, int width, int height,
+                                int startAngle, int arcAngle)
+    {
+        logger.log(POILogger.WARN,"fillArc not supported");
+    }
+
+    public void fillOval(int x, int y, int width, int height)
+    {
+        HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor( x, y, x + width, y + height ) );
+        shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_OVAL);
+        shape.setLineStyle(HSSFShape.LINESTYLE_NONE);
+        shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+    }
+
+    public void fillPolygon(int xPoints[], int yPoints[],
+                                    int nPoints)
+    {
+        int right  = findBiggest(xPoints);
+        int bottom = findBiggest(yPoints);
+        int left   = findSmallest(xPoints);
+        int top    = findSmallest(yPoints);
+        HSSFPolygon shape = escherGroup.createPolygon(new HSSFChildAnchor(left,top,right,bottom) );
+        shape.setPolygonDrawArea(right - left, bottom - top);
+        shape.setPoints(addToAll(xPoints, -left), addToAll(yPoints, -top));
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+        shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+    }
+
+    private int findBiggest( int[] values )
+    {
+        int result = Integer.MIN_VALUE;
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if (values[i] > result)
+                result = values[i];
+        }
+        return result;
+    }
+
+    private int findSmallest( int[] values )
+    {
+        int result = Integer.MAX_VALUE;
+        for ( int i = 0; i < values.length; i++ )
+        {
+            if (values[i] < result)
+                result = values[i];
+        }
+        return result;
+    }
+
+    public void fillRect(int x, int y, int width, int height)
+    {
+        HSSFSimpleShape shape = escherGroup.createShape(new HSSFChildAnchor( x, y, x + width, y + height ) );
+        shape.setShapeType(HSSFSimpleShape.OBJECT_TYPE_RECTANGLE);
+        shape.setLineStyle(HSSFShape.LINESTYLE_NONE);
+        shape.setFillColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+        shape.setLineStyleColor(foreground.getRed(), foreground.getGreen(), foreground.getBlue());
+    }
+
+    public void fillRoundRect(int x, int y, int width, int height,
+                                      int arcWidth, int arcHeight)
+    {
+        logger.log(POILogger.WARN,"fillRoundRect not supported");
+    }
+
+    public Shape getClip()
+    {
+        return getClipBounds();
+    }
+
+    public Rectangle getClipBounds()
+    {
+        return null;
+    }
+
+    public Rectangle getClipRect()
+    {
+        return getClipBounds();
+    }
+
+    public Color getColor()
+    {
+        return foreground;
+    }
+
+    public Font getFont()
+    {
+        return font;
+    }
+
+    public FontMetrics getFontMetrics(Font f)
+    {
+        return Toolkit.getDefaultToolkit().getFontMetrics(f);
+    }
+
+    public void setClip(int x, int y, int width, int height)
+    {
+        setClip(((Shape) (new Rectangle(x,y,width,height))));
+    }
+
+    public void setClip(Shape shape)
+    {
+        // ignore... not implemented
+    }
+
+    public void setColor(Color color)
+    {
+        foreground = color;
+    }
+
+    public void setFont(Font f)
+    {
+        font = f;
+    }
+
+    public void setPaintMode()
+    {
+        logger.log(POILogger.WARN,"setPaintMode not supported");
+    }
+
+    public void setXORMode(Color color)
+    {
+        logger.log(POILogger.WARN,"setXORMode not supported");
+    }
+
+    public void translate(int x, int y)
+    {
+        logger.log(POILogger.WARN,"translate not supported");
+    }
+
+    public Color getBackground()
+    {
+        return background;
+    }
+
+    public void setBackground( Color background )
+    {
+        this.background = background;
+    }
+
+
+}
+
diff --git a/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java b/src/java/org/apache/poi/hssf/usermodel/EscherGraphics2d.java
new file mode 100644 (file)
index 0000000..f3298d7
--- /dev/null
@@ -0,0 +1,567 @@
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.util.POILogFactory;
+import org.apache.poi.util.POILogger;
+
+import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.font.TextLayout;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.image.BufferedImage;
+import java.awt.image.BufferedImageOp;
+import java.awt.image.ImageObserver;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.RenderableImage;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+/**
+ * Translates Graphics2d calls into escher calls.  The translation is lossy so
+ * many features are not supported and some just aren't implemented yet.  If
+ * in doubt test the specific calls you wish to make. Graphics calls are
+ * always drawn into an EscherGroup so one will need to be created.
+ * <p>
+ * <b>Important:</b>
+ * <blockquote>
+ * One important concept worth considering is that of font size.  One of the
+ * difficulties in converting Graphics calls into escher drawing calls is that
+ * Excel does not have the concept of absolute pixel positions.  It measures
+ * it's cell widths in 'characters' and the cell heights in points.
+ * Unfortunately it's not defined exactly what a type of character it's
+ * measuring.  Presumably this is due to the fact that the Excel will be
+ * using different fonts on different platforms or even within the same
+ * platform.
+ * <p>
+ * Because of this constraint you have to calculate the verticalPointsPerPixel.
+ * This the amount the font should be scaled by when
+ * you issue commands such as drawString().  A good way to calculate this
+ * is to use the follow formula:
+ * <p>
+ * <pre>
+ *      multipler = groupHeightInPoints / heightOfGroup
+ * </pre>
+ * <p>
+ * The height of the group is calculated fairly simply by calculating the
+ * difference between the y coordinates of the bounding box of the shape.  The
+ * height of the group can be calculated by using a convenience called
+ * <code>HSSFClientAnchor.getAnchorHeightInPoints()</code>.
+ * </blockquote>
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class EscherGraphics2d extends Graphics2D
+{
+    private EscherGraphics escherGraphics;
+    private BufferedImage img;
+    private AffineTransform trans;
+    private Stroke stroke;
+    private Paint paint;
+    private Shape deviceclip;
+    private POILogger logger = POILogFactory.getLogger(getClass());
+
+    /**
+     * Constructs one escher graphics object from an escher graphics object.
+     *
+     * @param escherGraphics    the original EscherGraphics2d object to copy
+     */
+    public EscherGraphics2d(EscherGraphics escherGraphics)
+    {
+        this.escherGraphics = escherGraphics;
+        setImg( new BufferedImage(1, 1, 2) );
+        setColor(Color.black);
+    }
+
+    public void addRenderingHints(Map map)
+    {
+        getG2D().addRenderingHints(map);
+    }
+
+    public void clearRect(int i, int j, int k, int l)
+    {
+        Paint paint1 = getPaint();
+        setColor(getBackground());
+        fillRect(i, j, k, l);
+        setPaint(paint1);
+    }
+
+    public void clip(Shape shape)
+    {
+        if(getDeviceclip() != null)
+        {
+            Area area = new Area(getClip());
+            if(shape != null)
+                area.intersect(new Area(shape));
+            shape = area;
+        }
+        setClip(shape);
+    }
+
+    public void clipRect(int x, int y, int width, int height)
+    {
+        clip(new Rectangle(x,y,width,height));
+    }
+
+    public void copyArea(int x, int y, int width, int height,
+                                 int dx, int dy)
+    {
+        getG2D().copyArea(x,y,width,height,dx,dy);
+    }
+
+    public Graphics create()
+    {
+        EscherGraphics2d g2d = new EscherGraphics2d(escherGraphics);
+        return g2d;
+    }
+
+    public void dispose()
+    {
+        getEscherGraphics().dispose();
+        getG2D().dispose();
+        getImg().flush();
+    }
+
+    public void draw(Shape shape)
+    {
+        logger.log(POILogger.WARN,"copyArea not supported");
+    }
+
+    public void drawArc(int x, int y, int width, int height,
+                                int startAngle, int arcAngle)
+    {
+        draw(new java.awt.geom.Arc2D.Float(x, y, width, height, startAngle, arcAngle, 0));
+    }
+
+    public void drawGlyphVector(GlyphVector g, float x, float y)
+    {
+        fill(g.getOutline(x, y));
+    }
+
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
+            int sx2, int sy2, Color bgColor, ImageObserver imageobserver)
+    {
+        logger.log(POILogger.WARN,"drawImage() not supported");
+        return true;
+    }
+
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
+            int sx2, int sy2, ImageObserver imageobserver)
+    {
+        logger.log(POILogger.WARN,"drawImage() not supported");
+        return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, imageobserver);
+    }
+    public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, Color bgColor, ImageObserver imageobserver)
+    {
+        logger.log(POILogger.WARN,"drawImage() not supported");
+        return true;
+    }
+
+    public boolean drawImage(Image img, int x, int y,
+                                     int width, int height,
+                                     ImageObserver observer)
+    {
+        return drawImage(img, x,y,width,height, null, observer);
+    }
+
+    public boolean drawImage(Image image, int x, int y, Color bgColor, ImageObserver imageobserver)
+    {
+        return drawImage(image, x, y, image.getWidth(imageobserver), image.getHeight(imageobserver), bgColor, imageobserver);
+    }
+
+    public boolean drawImage(Image image, int x, int y, ImageObserver imageobserver)
+    {
+        return drawImage(image, x, y, image.getWidth(imageobserver), image.getHeight(imageobserver), imageobserver);
+    }
+
+    public boolean drawImage(Image image, AffineTransform affinetransform, ImageObserver imageobserver)
+    {
+        AffineTransform affinetransform1 = (AffineTransform)getTrans().clone();
+        getTrans().concatenate(affinetransform);
+        drawImage(image, 0, 0, imageobserver);
+        setTrans( affinetransform1 );
+        return true;
+    }
+
+    public void drawImage(BufferedImage bufferedimage, BufferedImageOp op, int x, int y)
+    {
+        BufferedImage img = op.filter(bufferedimage, null);
+        drawImage(((Image) (img)), new AffineTransform(1.0F, 0.0F, 0.0F, 1.0F, x, y), null);
+    }
+
+    public void drawLine(int x1, int y1, int x2, int y2)
+    {
+        getEscherGraphics().drawLine(x1,y1,x2,y2);
+//        draw(new GeneralPath(new java.awt.geom.Line2D.Float(x1, y1, x2, y2)));
+    }
+
+    public void drawOval(int x, int y, int width, int height)
+    {
+        getEscherGraphics().drawOval(x,y,width,height);
+//        draw(new java.awt.geom.Ellipse2D.Float(x, y, width, height));
+    }
+
+    public void drawPolygon(int xPoints[], int yPoints[],
+                                    int nPoints)
+    {
+        getEscherGraphics().drawPolygon(xPoints, yPoints, nPoints);
+    }
+
+    public void drawPolyline(int xPoints[], int yPoints[], int nPoints)
+    {
+        if(nPoints > 0)
+        {
+            GeneralPath generalpath = new GeneralPath();
+            generalpath.moveTo(xPoints[0], yPoints[0]);
+            for(int j = 1; j < nPoints; j++)
+                generalpath.lineTo(xPoints[j], yPoints[j]);
+
+            draw(generalpath);
+        }
+    }
+
+    public void drawRect(int x, int y, int width, int height)
+    {
+        escherGraphics.drawRect(x,y,width,height);
+    }
+
+    public void drawRenderableImage(RenderableImage renderableimage, AffineTransform affinetransform)
+    {
+        drawRenderedImage(renderableimage.createDefaultRendering(), affinetransform);
+    }
+
+    public void drawRenderedImage(RenderedImage renderedimage, AffineTransform affinetransform)
+    {
+        BufferedImage bufferedimage = new BufferedImage(renderedimage.getColorModel(), renderedimage.getData().createCompatibleWritableRaster(), false, null);
+        bufferedimage.setData(renderedimage.getData());
+        drawImage(bufferedimage, affinetransform, null);
+    }
+
+    public void drawRoundRect(int i, int j, int k, int l, int i1, int j1)
+    {
+        draw(new java.awt.geom.RoundRectangle2D.Float(i, j, k, l, i1, j1));
+    }
+
+    public void drawString(String string, float x, float y)
+    {
+        getEscherGraphics().drawString(string, (int)x, (int)y);
+    }
+
+    public void drawString(String string, int x, int y)
+    {
+        getEscherGraphics().drawString(string, x, y);
+    }
+
+    public void drawString(AttributedCharacterIterator attributedcharacteriterator, float x, float y)
+    {
+        TextLayout textlayout = new TextLayout(attributedcharacteriterator, getFontRenderContext());
+        Paint paint1 = getPaint();
+        setColor(getColor());
+        fill(textlayout.getOutline(AffineTransform.getTranslateInstance(x, y)));
+        setPaint(paint1);
+    }
+
+    public void drawString(AttributedCharacterIterator attributedcharacteriterator, int x, int y)
+    {
+        drawString(attributedcharacteriterator, x, y);
+    }
+
+    public void fill(Shape shape)
+    {
+        logger.log(POILogger.WARN,"fill(Shape) not supported");
+    }
+
+    public void fillArc(int i, int j, int k, int l, int i1, int j1)
+    {
+        fill(new java.awt.geom.Arc2D.Float(i, j, k, l, i1, j1, 2));
+    }
+
+    public void fillOval(int x, int y, int width, int height)
+    {
+        escherGraphics.fillOval(x,y,width,height);
+    }
+
+    /**
+     * Fills a closed polygon defined by
+     * arrays of <i>x</i> and <i>y</i> coordinates.
+     * <p>
+     * This method draws the polygon defined by <code>nPoint</code> line
+     * segments, where the first <code>nPoint&nbsp;-&nbsp;1</code>
+     * line segments are line segments from
+     * <code>(xPoints[i&nbsp;-&nbsp;1],&nbsp;yPoints[i&nbsp;-&nbsp;1])</code>
+     * to <code>(xPoints[i],&nbsp;yPoints[i])</code>, for
+     * 1&nbsp;&le;&nbsp;<i>i</i>&nbsp;&le;&nbsp;<code>nPoints</code>.
+     * The figure is automatically closed by drawing a line connecting
+     * the final point to the first point, if those points are different.
+     * <p>
+     * The area inside the polygon is defined using an
+     * even-odd fill rule, also known as the alternating rule.
+     * @param        xPoints   a an array of <code>x</code> coordinates.
+     * @param        yPoints   a an array of <code>y</code> coordinates.
+     * @param        nPoints   a the total number of points.
+     * @see          java.awt.Graphics#drawPolygon(int[], int[], int)
+     */
+    public void fillPolygon(int xPoints[], int yPoints[], int nPoints)
+    {
+        escherGraphics.fillPolygon(xPoints, yPoints, nPoints);
+    }
+
+    public void fillRect(int x, int y, int width, int height)
+    {
+        getEscherGraphics().fillRect(x,y,width,height);
+    }
+
+    public void fillRoundRect(int x, int y, int width, int height,
+                                      int arcWidth, int arcHeight)
+    {
+        fill(new java.awt.geom.RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight));
+    }
+
+    public Color getBackground()
+    {
+        return getEscherGraphics().getBackground();
+    }
+
+    public Shape getClip()
+    {
+        try
+        {
+            return getTrans().createInverse().createTransformedShape(getDeviceclip());
+        }
+        catch(Exception _ex)
+        {
+            return null;
+        }
+    }
+
+    public Rectangle getClipBounds()
+    {
+        if(getDeviceclip() != null)
+            return getClip().getBounds();
+        else
+            return null;
+    }
+
+    public Color getColor()
+    {
+        return escherGraphics.getColor();
+    }
+
+    public Composite getComposite()
+    {
+        return getG2D().getComposite();
+    }
+
+    public GraphicsConfiguration getDeviceConfiguration()
+    {
+        return getG2D().getDeviceConfiguration();
+    }
+
+    public Font getFont()
+    {
+        return getEscherGraphics().getFont();
+    }
+
+    public FontMetrics getFontMetrics(Font font)
+    {
+        return getEscherGraphics().getFontMetrics(font);
+    }
+
+    public FontRenderContext getFontRenderContext()
+    {
+        getG2D().setTransform(getTrans());
+        return getG2D().getFontRenderContext();
+    }
+
+    public Paint getPaint()
+    {
+        return paint;
+    }
+
+    public Object getRenderingHint(java.awt.RenderingHints.Key key)
+    {
+        return getG2D().getRenderingHint(key);
+    }
+
+    public RenderingHints getRenderingHints()
+    {
+        return getG2D().getRenderingHints();
+    }
+
+    public Stroke getStroke()
+    {
+        return stroke;
+    }
+
+    public AffineTransform getTransform()
+    {
+        return (AffineTransform)getTrans().clone();
+    }
+
+    public boolean hit(Rectangle rectangle, Shape shape, boolean flag)
+    {
+        getG2D().setTransform(getTrans());
+        getG2D().setStroke(getStroke());
+        getG2D().setClip(getClip());
+        return getG2D().hit(rectangle, shape, flag);
+    }
+
+    public void rotate(double d)
+    {
+        getTrans().rotate(d);
+    }
+
+    public void rotate(double d, double d1, double d2)
+    {
+        getTrans().rotate(d, d1, d2);
+    }
+
+    public void scale(double d, double d1)
+    {
+        getTrans().scale(d, d1);
+    }
+
+    public void setBackground(Color c)
+    {
+        getEscherGraphics().setBackground(c);
+    }
+
+    public void setClip(int i, int j, int k, int l)
+    {
+        setClip(((Shape) (new Rectangle(i, j, k, l))));
+    }
+
+    public void setClip(Shape shape)
+    {
+        setDeviceclip( getTrans().createTransformedShape(shape) );
+    }
+
+    public void setColor(Color c)
+    {
+        escherGraphics.setColor(c);
+    }
+
+    public void setComposite(Composite composite)
+    {
+        getG2D().setComposite(composite);
+    }
+
+    public void setFont(Font font)
+    {
+        getEscherGraphics().setFont(font);
+    }
+
+    public void setPaint(Paint paint1)
+    {
+        if(paint1 != null)
+        {
+            paint = paint1;
+            if(paint1 instanceof Color)
+                setColor( (Color)paint1 );
+        }
+    }
+
+    public void setPaintMode()
+    {
+        getEscherGraphics().setPaintMode();
+    }
+
+    public void setRenderingHint(java.awt.RenderingHints.Key key, Object obj)
+    {
+        getG2D().setRenderingHint(key, obj);
+    }
+
+    public void setRenderingHints(Map map)
+    {
+        getG2D().setRenderingHints(map);
+    }
+
+    public void setStroke(Stroke s)
+    {
+        stroke = s;
+    }
+
+    public void setTransform(AffineTransform affinetransform)
+    {
+        setTrans( (AffineTransform)affinetransform.clone() );
+    }
+
+    public void setXORMode(Color color1)
+    {
+        getEscherGraphics().setXORMode(color1);
+    }
+
+    public void shear(double d, double d1)
+    {
+        getTrans().shear(d, d1);
+    }
+
+    public void transform(AffineTransform affinetransform)
+    {
+        getTrans().concatenate(affinetransform);
+    }
+
+//    Image transformImage(Image image, Rectangle rectangle, Rectangle rectangle1, ImageObserver imageobserver, Color color1)
+//    {
+//        logger.log(POILogger.WARN,"transformImage() not supported");
+//        return null;
+//    }
+//
+//    Image transformImage(Image image, int ai[], Rectangle rectangle, ImageObserver imageobserver, Color color1)
+//    {
+//        logger.log(POILogger.WARN,"transformImage() not supported");
+//        return null;
+//    }
+
+    public void translate(double d, double d1)
+    {
+        getTrans().translate(d, d1);
+    }
+
+    public void translate(int i, int j)
+    {
+        getTrans().translate(i, j);
+    }
+
+    private EscherGraphics getEscherGraphics()
+    {
+        return escherGraphics;
+    }
+
+    private BufferedImage getImg()
+    {
+        return img;
+    }
+
+    private void setImg( BufferedImage img )
+    {
+        this.img = img;
+    }
+
+    private Graphics2D getG2D()
+    {
+        return (Graphics2D) img.getGraphics();
+    }
+
+    private AffineTransform getTrans()
+    {
+        return trans;
+    }
+
+    private void setTrans( AffineTransform trans )
+    {
+        this.trans = trans;
+    }
+
+    private Shape getDeviceclip()
+    {
+        return deviceclip;
+    }
+
+    private void setDeviceclip( Shape deviceclip )
+    {
+        this.deviceclip = deviceclip;
+    }
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/FontDetails.java b/src/java/org/apache/poi/hssf/usermodel/FontDetails.java
new file mode 100644 (file)
index 0000000..96b0d87
--- /dev/null
@@ -0,0 +1,143 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+/**
+ * Stores width and height details about a font.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class FontDetails
+{
+    private String fontName;
+    private int height;
+    private Map charWidths = new HashMap();
+
+    /**
+     * Construct the font details with the given name and height.
+     *
+     * @param fontName  The font name.
+     * @param height    The height of the font.
+     */
+    public FontDetails( String fontName, int height )
+    {
+        this.fontName = fontName;
+        this.height = height;
+    }
+
+    public String getFontName()
+    {
+        return fontName;
+    }
+
+    public int getHeight()
+    {
+        return height;
+    }
+
+    public void addChar( char c, int width )
+    {
+        charWidths.put(new Character(c), new Integer(width));
+    }
+
+    /**
+     * Retrieves the width of the specified character.  If the metrics for
+     * a particular character are not available it defaults to returning the
+     * width for the 'W' character.
+     */
+    public int getCharWidth( char c )
+    {
+        Integer widthInteger = (Integer)(charWidths.get(new Character(c)));
+        if (widthInteger == null && c != 'W')
+            return getCharWidth('W');
+        else
+            return widthInteger.intValue();
+    }
+
+    public void addChars( char[] characters, int[] widths )
+    {
+        for ( int i = 0; i < characters.length; i++ )
+        {
+            charWidths.put( new Character(characters[i]), new Integer(widths[i]));
+        }
+    }
+
+    /**
+     * Create an instance of <code>FontDetails</code> by loading them from the
+     * provided property object.
+     * @param fontName          the font name
+     * @param fontMetricsProps  the property object holding the details of this
+     *                          particular font.
+     * @return  a new FontDetails instance.
+     */
+    public static FontDetails create( String fontName, Properties fontMetricsProps )
+    {
+        String heightStr = fontMetricsProps.getProperty( "font." + fontName + ".height");
+        String widthsStr = fontMetricsProps.getProperty( "font." + fontName + ".widths");
+        String charactersStr = fontMetricsProps.getProperty( "font." + fontName + ".characters");
+        int height = Integer.parseInt(heightStr);
+        FontDetails d = new FontDetails(fontName, height);
+        String[] charactersStrArray = split(charactersStr, ",", -1);
+        String[] widthsStrArray = split(widthsStr, ",", -1);
+        if (charactersStrArray.length != widthsStrArray.length)
+            throw new RuntimeException("Number of characters does not number of widths for font " + fontName);
+        for ( int i = 0; i < widthsStrArray.length; i++ )
+        {
+            if (charactersStrArray[i].length() != 0)
+                d.addChar(charactersStrArray[i].charAt(0), Integer.parseInt(widthsStrArray[i]));
+        }
+        return d;
+    }
+
+    /**
+     * Gets the width of all characters in a string.
+     *
+     * @param str   The string to measure.
+     * @return      The width of the string for a 10 point font.
+     */
+    public int getStringWidth(String str)
+    {
+        int width = 0;
+        for (int i = 0; i < str.length(); i++)
+        {
+            width += getCharWidth(str.charAt(i));
+        }
+        return width;
+    }
+
+    /**
+     * Split the given string into an array of strings using the given
+     * delimiter.
+     */
+    private static String[] split(String text, String separator, int max)
+    {
+        StringTokenizer tok = new StringTokenizer(text, separator);
+        int listSize = tok.countTokens();
+        if(max != -1 && listSize > max)
+            listSize = max;
+        String list[] = new String[listSize];
+        for(int i = 0; tok.hasMoreTokens(); i++)
+        {
+            if(max != -1 && i == listSize - 1)
+            {
+                StringBuffer buf = new StringBuffer((text.length() * (listSize - i)) / listSize);
+                while(tok.hasMoreTokens())
+                {
+                    buf.append(tok.nextToken());
+                    if(tok.hasMoreTokens())
+                        buf.append(separator);
+                }
+                list[i] = buf.toString().trim();
+                break;
+            }
+            list[i] = tok.nextToken().trim();
+        }
+
+        return list;
+    }
+
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFAnchor.java
new file mode 100644 (file)
index 0000000..b9db3c7
--- /dev/null
@@ -0,0 +1,40 @@
+package org.apache.poi.hssf.usermodel;
+
+
+/**
+ * An anchor is what specifics the position of a shape within a client object
+ * or within another containing shape.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public abstract class HSSFAnchor
+{
+    int dx1;
+    int dy1;
+    int dx2;
+    int dy2;
+
+    public HSSFAnchor()
+    {
+    }
+
+    public HSSFAnchor( int dx1, int dy1, int dx2, int dy2 )
+    {
+        this.dx1 = dx1;
+        this.dy1 = dy1;
+        this.dx2 = dx2;
+        this.dy2 = dy2;
+    }
+
+    public int getDx1(){ return dx1; }
+    public void setDx1( int dx1 ){ this.dx1 = dx1; }
+    public int getDy1(){ return dy1; }
+    public void setDy1( int dy1 ){ this.dy1 = dy1; }
+    public int getDy2(){ return dy2; }
+    public void setDy2( int dy2 ){ this.dy2 = dy2; }
+    public int getDx2(){ return dx2; }
+    public void setDx2( int dx2 ){ this.dx2 = dx2; }
+
+    public abstract boolean isHorizontallyFlipped();
+    public abstract boolean isVerticallyFlipped();
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFChildAnchor.java
new file mode 100644 (file)
index 0000000..fd69f48
--- /dev/null
@@ -0,0 +1,37 @@
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.ddf.EscherRecord;
+import org.apache.poi.ddf.EscherClientAnchorRecord;
+import org.apache.poi.ddf.EscherChildAnchorRecord;
+
+public class HSSFChildAnchor
+        extends HSSFAnchor
+{
+    public HSSFChildAnchor()
+    {
+    }
+
+    public HSSFChildAnchor( int dx1, int dy1, int dx2, int dy2 )
+    {
+        super( dx1, dy1, dx2, dy2 );
+    }
+
+    public void setAnchor(int dx1, int dy1, int dx2, int dy2)
+    {
+        this.dx1 = dx1;
+        this.dy1 = dy1;
+        this.dx2 = dx2;
+        this.dy2 = dy2;
+    }
+
+    public boolean isHorizontallyFlipped()
+    {
+        return dx1 > dx2;
+    }
+
+    public boolean isVerticallyFlipped()
+    {
+        return dy1 > dy2;
+    }
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java b/src/java/org/apache/poi/hssf/usermodel/HSSFClientAnchor.java
new file mode 100644 (file)
index 0000000..cbbaf16
--- /dev/null
@@ -0,0 +1,207 @@
+package org.apache.poi.hssf.usermodel;
+
+import org.apache.poi.ddf.EscherClientAnchorRecord;
+import org.apache.poi.ddf.EscherRecord;
+
+
+/**
+ * A client anchor is attached to an excel worksheet.  It anchors against a
+ * top-left and buttom-right cell.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFClientAnchor
+        extends HSSFAnchor
+{
+    short col1;
+    int row1;
+    short col2;
+    int row2;
+
+    /**
+     * Creates a new client anchor and defaults all the anchor positions to 0.
+     */
+    public HSSFClientAnchor()
+    {
+    }
+
+    /**
+     * Creates a new client anchor and sets the top-left and bottom-right
+     * coordinates of the anchor.
+     *
+     * @param dx1   the x coordinate within the first cell.
+     * @param dy1   the y coordinate within the first cell.
+     * @param dx2   the x coordinate within the second cell.
+     * @param dy2   the y coordinate within the second cell.
+     * @param col1  the column (0 based) of the first cell.
+     * @param row1  the row (0 based) of the first cell.
+     * @param col2  the column (0 based) of the second cell.
+     * @param row2  the row (0 based) of the second cell.
+     */
+    public HSSFClientAnchor( int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2 )
+    {
+        super( dx1, dy1, dx2, dy2 );
+
+        checkRange(dx1, 0, 1023, "dx1");
+        checkRange(dx2, 0, 1023, "dx2");
+        checkRange(dy1, 0, 255, "dy1");
+        checkRange(dy2, 0, 255, "dy2");
+        checkRange(col1, 0, 255, "col1");
+        checkRange(col2, 0, 255, "col2");
+        checkRange(row1, 0, 255 * 256, "row1");
+        checkRange(row2, 0, 255 * 256, "row2");
+
+        this.col1 = col1;
+        this.row1 = row1;
+        this.col2 = col2;
+        this.row2 = row2;
+    }
+
+    /**
+     * Calculates the height of a client anchor in points.
+     *
+     * @param sheet     the sheet the anchor will be attached to
+     * @return          the shape height.
+     */
+    public float getAnchorHeightInPoints(HSSFSheet sheet )
+    {
+        int y1 = Math.min( getDy1(), getDy2() );
+        int y2 = Math.max( getDy1(), getDy2() );
+        int row1 = Math.min( getRow1(), getRow2() );
+        int row2 = Math.max( getRow1(), getRow2() );
+
+        float points = 0;
+        if (row1 == row2)
+        {
+            points = ((y2 - y1) / 256.0f) * getRowHeightInPoints(sheet, row2);
+        }
+        else
+        {
+            points += ((256.0f - y1) / 256.0f) * getRowHeightInPoints(sheet, row1);
+            for (int i = row1 + 1; i < row2; i++)
+            {
+                points += getRowHeightInPoints(sheet, i);
+            }
+            points += (y2 / 256.0f) * getRowHeightInPoints(sheet, row2);
+        }
+
+        return points;
+    }
+
+    private float getRowHeightInPoints(HSSFSheet sheet, int rowNum)
+    {
+        HSSFRow row = sheet.getRow(rowNum);
+        if (row == null)
+            return sheet.getDefaultRowHeightInPoints();
+        else
+            return row.getHeightInPoints();
+    }
+
+    public short getCol1()
+    {
+        return col1;
+    }
+
+    public void setCol1( short col1 )
+    {
+        checkRange(col1, 0, 255, "col1");
+        this.col1 = col1;
+    }
+
+    public short getCol2()
+    {
+        return col2;
+    }
+
+    public void setCol2( short col2 )
+    {
+        checkRange(col2, 0, 255, "col2");
+        this.col2 = col2;
+    }
+
+    public int getRow1()
+    {
+        return row1;
+    }
+
+    public void setRow1( int row1 )
+    {
+        checkRange(row1, 0, 256 * 256, "row1");
+        this.row1 = row1;
+    }
+
+    public int getRow2()
+    {
+        return row2;
+    }
+
+    public void setRow2( int row2 )
+    {
+        checkRange(row2, 0, 256 * 256, "row2");
+        this.row2 = row2;
+    }
+
+    /**
+     * Dets the top-left and bottom-right
+     * coordinates of the anchor.
+     *
+     * @param x1   the x coordinate within the first cell.
+     * @param y1   the y coordinate within the first cell.
+     * @param x2   the x coordinate within the second cell.
+     * @param y2   the y coordinate within the second cell.
+     * @param col1  the column (0 based) of the first cell.
+     * @param row1  the row (0 based) of the first cell.
+     * @param col2  the column (0 based) of the second cell.
+     * @param row2  the row (0 based) of the second cell.
+     */
+    public void setAnchor( short col1, int row1, int x1, int y1, short col2, int row2, int x2, int y2 )
+    {
+        checkRange(dx1, 0, 1023, "dx1");
+        checkRange(dx2, 0, 1023, "dx2");
+        checkRange(dy1, 0, 255, "dy1");
+        checkRange(dy2, 0, 255, "dy2");
+        checkRange(col1, 0, 255, "col1");
+        checkRange(col2, 0, 255, "col2");
+        checkRange(row1, 0, 255 * 256, "row1");
+        checkRange(row2, 0, 255 * 256, "row2");
+
+        this.col1 = col1;
+        this.row1 = row1;
+        this.dx1 = x1;
+        this.dy1 = y1;
+        this.col2 = col2;
+        this.row2 = row2;
+        this.dx2 = x2;
+        this.dy2 = y2;
+    }
+
+    /**
+     * @return  true if the anchor goes from right to left.
+     */
+    public boolean isHorizontallyFlipped()
+    {
+        if (col1 == col2)
+            return dx1 > dx2;
+        else
+            return col1 > col2;
+    }
+
+    /**
+     * @return  true if the anchor goes from bottom to top.
+     */
+    public boolean isVerticallyFlipped()
+    {
+        if (row1 == row2)
+            return dy1 > dy2;
+        else
+            return row1 > row2;
+    }
+
+    private void checkRange( int value, int minRange, int maxRange, String varName )
+    {
+        if (value < minRange || value > maxRange)
+            throw new IllegalArgumentException(varName + " must be between " + minRange + " and " + maxRange);
+    }
+
+
+}
index 61b8c60de757578fdc24b4d5ac34d669699244d6..7485b0bb2ef1e1c69d1b5c82cdf80bb6e8486fe6 100644 (file)
@@ -165,7 +165,7 @@ public class HSSFFont
 
     /**
      * set the name for the font (i.e. Arial)
-     * @param String representing the name of the font to use
+     * @param name  String representing the name of the font to use
      * @see #FONT_ARIAL
      */
 
@@ -359,7 +359,7 @@ public class HSSFFont
 
     /**
      * set type of text underlining to use
-     * @param underlining type
+     * @param underline type
      * @see #U_NONE
      * @see #U_SINGLE
      * @see #U_DOUBLE
@@ -386,4 +386,13 @@ public class HSSFFont
     {
         return font.getUnderline();
     }
+
+    public String toString()
+    {
+        return "org.apache.poi.hssf.usermodel.HSSFFont{" +
+                 font +
+                "}";
+    }
+
+
 }
index 863533d45588b5e8110c010ce895b74ddc78e968..d4554fd75087d4d1ee738be1ba39749dd92bd24a 100644 (file)
@@ -110,7 +110,35 @@ public class HSSFPalette
         }
         return null;
     }
-    
+
+    /**
+     * Finds the closest matching color in the custom palette.  The
+     * method for finding the distance between the colors is fairly
+     * primative.
+     *
+     * @param red   The red component of the color to match.
+     * @param green The green component of the color to match.
+     * @param blue  The blue component of the color to match.
+     * @return  The closest color or null if there are no custom
+     *          colors currently defined.
+     */
+    public HSSFColor findSimilarColor(byte red, byte green, byte blue)
+    {
+        HSSFColor result = null;
+        int minColorDistance = Integer.MAX_VALUE;
+        byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
+        for (short i = (short) PaletteRecord.FIRST_COLOR_INDEX; b != null;
+            b = palette.getColor(++i))
+        {
+            int colorDistance = red - b[0] + green - b[1] + blue - b[2];
+            if (colorDistance < minColorDistance)
+            {
+                result = getColor(i);
+            }
+        }
+        return result;
+    }
+
     /**
      * Sets the color at the given offset
      *
@@ -123,7 +151,32 @@ public class HSSFPalette
     {
         palette.setColor(index, red, green, blue);
     }
-    
+
+    /**
+     * Adds a new color into an empty color slot.
+     * @param red       The red component
+     * @param green     The green component
+     * @param blue      The blue component
+     *
+     * @return  The new custom color.
+     *
+     * @throws RuntimeException if there are more more free color indexes.
+     */
+    public HSSFColor addColor( byte red, byte green, byte blue )
+    {
+        byte[] b = palette.getColor(PaletteRecord.FIRST_COLOR_INDEX);
+        short i;
+        for (i = (short) PaletteRecord.FIRST_COLOR_INDEX; i < PaletteRecord.STANDARD_PALETTE_SIZE + PaletteRecord.FIRST_COLOR_INDEX; b = palette.getColor(++i))
+        {
+            if (b == null)
+            {
+                setColorAtIndex( i, red, green, blue );
+                return getColor(i);
+            }
+        }
+        throw new RuntimeException("Could not find free color index");
+    }
+
     private static class CustomColor extends HSSFColor
     {
         private short byteOffset;
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPatriarch.java
new file mode 100644 (file)
index 0000000..d0a376c
--- /dev/null
@@ -0,0 +1,159 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * The patriarch is the toplevel container for shapes in a sheet.  It does
+ * little other than act as a container for other shapes and groups.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFPatriarch
+        implements HSSFShapeContainer
+{
+    List shapes = new ArrayList();
+    HSSFSheet sheet;
+    int x1 = 0;
+    int y1  = 0 ;
+    int x2 = 1023;
+    int y2 = 255;
+
+    /**
+     * Creates the patriarch.
+     *
+     * @param sheet     the sheet this patriarch is stored in.
+     */
+    HSSFPatriarch(HSSFSheet sheet)
+    {
+        this.sheet = sheet;
+    }
+
+    /**
+     * Creates a new group record stored under this patriarch.
+     *
+     * @param anchor    the client anchor describes how this group is attached
+     *                  to the sheet.
+     * @return  the newly created group.
+     */
+    public HSSFShapeGroup createGroup(HSSFClientAnchor anchor)
+    {
+        HSSFShapeGroup group = new HSSFShapeGroup(null, anchor);
+        group.anchor = anchor;
+        shapes.add(group);
+        return group;
+    }
+
+    /**
+     * Creates a simple shape.  This includes such shapes as lines, rectangles,
+     * and ovals.
+     *
+     * @param anchor    the client anchor describes how this group is attached
+     *                  to the sheet.
+     * @return  the newly created shape.
+     */
+    public HSSFSimpleShape createSimpleShape(HSSFClientAnchor anchor)
+    {
+        HSSFSimpleShape shape = new HSSFSimpleShape(null, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Creates a polygon
+     *
+     * @param anchor    the client anchor describes how this group is attached
+     *                  to the sheet.
+     * @return  the newly created shape.
+     */
+    public HSSFPolygon createPolygon(HSSFClientAnchor anchor)
+    {
+        HSSFPolygon shape = new HSSFPolygon(null, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Constructs a textbox under the patriarch.
+     *
+     * @param anchor    the client anchor describes how this group is attached
+     *                  to the sheet.
+     * @return      the newly created textbox.
+     */
+    public HSSFTextbox createTextbox(HSSFClientAnchor anchor)
+    {
+        HSSFTextbox shape = new HSSFTextbox(null, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Returns a list of all shapes contained by the patriarch.
+     */
+    public List getChildren()
+    {
+        return shapes;
+    }
+
+    /**
+     * Total count of all children and their children's children.
+     */
+    public int countOfAllChildren()
+    {
+        int count = shapes.size();
+        for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
+        {
+            HSSFShape shape = (HSSFShape) iterator.next();
+            count += shape.countOfAllChildren();
+        }
+        return count;
+    }
+    /**
+     * Sets the coordinate space of this group.  All children are contrained
+     * to these coordinates.
+     */
+    public void setCoordinates( int x1, int y1, int x2, int y2 )
+    {
+        this.x1 = x1;
+        this.y1 = y1;
+        this.x2 = x2;
+        this.y2 = y2;
+    }
+
+    /**
+     * The top left x coordinate of this group.
+     */
+    public int getX1()
+    {
+        return x1;
+    }
+
+    /**
+     * The top left y coordinate of this group.
+     */
+    public int getY1()
+    {
+        return y1;
+    }
+
+    /**
+     * The bottom right x coordinate of this group.
+     */
+    public int getX2()
+    {
+        return x2;
+    }
+
+    /**
+     * The bottom right y coordinate of this group.
+     */
+    public int getY2()
+    {
+        return y2;
+    }
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java b/src/java/org/apache/poi/hssf/usermodel/HSSFPolygon.java
new file mode 100644 (file)
index 0000000..67f4532
--- /dev/null
@@ -0,0 +1,66 @@
+package org.apache.poi.hssf.usermodel;
+
+/**
+ * @author Glen Stampoultzis  (glens at superlinksoftware.com)
+ */
+public class HSSFPolygon
+        extends HSSFShape
+{
+    int[] xPoints;
+    int[] yPoints;
+    int drawAreaWidth = 100;
+    int drawAreaHeight = 100;
+
+    HSSFPolygon( HSSFShape parent, HSSFAnchor anchor )
+    {
+        super( parent, anchor );
+    }
+
+    public int[] getXPoints()
+    {
+        return xPoints;
+    }
+
+    public int[] getYPoints()
+    {
+        return yPoints;
+    }
+
+    public void setPoints(int[] xPoints, int[] yPoints)
+    {
+        this.xPoints = cloneArray(xPoints);
+        this.yPoints = cloneArray(yPoints);
+    }
+
+    private int[] cloneArray( int[] a )
+    {
+        int[] result = new int[a.length];
+        for ( int i = 0; i < a.length; i++ )
+            result[i] = a[i];
+
+        return result;
+    }
+
+    /**
+     * Defines the width and height of the points in the polygon
+     * @param width
+     * @param height
+     */
+    public void setPolygonDrawArea( int width, int height )
+    {
+        this.drawAreaWidth = width;
+        this.drawAreaHeight = height;
+    }
+
+    public int getDrawAreaWidth()
+    {
+        return drawAreaWidth;
+    }
+
+    public int getDrawAreaHeight()
+    {
+        return drawAreaHeight;
+    }
+
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java b/src/java/org/apache/poi/hssf/usermodel/HSSFRichTextString.java
new file mode 100644 (file)
index 0000000..59edf61
--- /dev/null
@@ -0,0 +1,179 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Rich text unicode string.  These strings can have fonts applied to
+ * arbitary parts of the string.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFRichTextString
+        implements Comparable
+{
+    /** Place holder for indicating that NO_FONT has been applied here */
+    public static final short NO_FONT = -1;
+
+    String string;
+    SortedMap formattingRuns = new TreeMap();
+
+    public HSSFRichTextString()
+    {
+        this("");
+    }
+
+    public HSSFRichTextString( String string )
+    {
+        this.string = string;
+        this.formattingRuns.put(new Integer(0), new Short(NO_FONT));
+    }
+
+    /**
+     * Applies a font to the specified characters of a string.
+     *
+     * @param startIndex    The start index to apply the font to (inclusive)
+     * @param endIndex      The end index to apply the font to (exclusive)
+     * @param fontIndex     The font to use.
+     */
+    public void applyFont(int startIndex, int endIndex, short fontIndex)
+    {
+        if (startIndex > endIndex)
+            throw new IllegalArgumentException("Start index must be less than end index.");
+        if (startIndex < 0 || endIndex > length())
+            throw new IllegalArgumentException("Start and end index not in range.");
+        if (startIndex == endIndex)
+            return;
+
+        Integer from = new Integer(startIndex);
+        Integer to = new Integer(endIndex);
+        short fontAtIndex = NO_FONT;
+        if (endIndex != length())
+            fontAtIndex = getFontAtIndex(endIndex);
+        formattingRuns.subMap(from, to).clear();
+        formattingRuns.put(from, new Short(fontIndex));
+        if (endIndex != length())
+        {
+            if (fontIndex != fontAtIndex)
+                formattingRuns.put(to, new Short(fontAtIndex));
+        }
+    }
+
+    /**
+     * Applies a font to the specified characters of a string.
+     *
+     * @param startIndex    The start index to apply the font to (inclusive)
+     * @param endIndex      The end index to apply to font to (exclusive)
+     * @param font          The index of the font to use.
+     */
+    public void applyFont(int startIndex, int endIndex, HSSFFont font)
+    {
+        applyFont(startIndex, endIndex, font.getIndex());
+    }
+
+    /**
+     * Sets the font of the entire string.
+     * @param font          The font to use.
+     */
+    public void applyFont(HSSFFont font)
+    {
+        applyFont(0, string.length(), font);
+    }
+
+    /**
+     * Returns the plain string representation.
+     */
+    public String getString()
+    {
+        return string;
+    }
+
+    /**
+     * @return  the number of characters in the font.
+     */
+    public int length()
+    {
+        return string.length();
+    }
+
+    /**
+     * Returns the font in use at a particular index.
+     *
+     * @param index         The index.
+     * @return              The font that's currently being applied at that
+     *                      index or null if no font is being applied or the
+     *                      index is out of range.
+     */
+    public short getFontAtIndex( int index )
+    {
+        if (index < 0 || index >= string.length())
+            throw new ArrayIndexOutOfBoundsException("Font index " + index + " out of bounds of string");
+        Integer key = new Integer(index + 1);
+        SortedMap head = formattingRuns.headMap(key);
+        if (head.isEmpty())
+            throw new IllegalStateException("Should not reach here.  No font found.");
+        else
+            return ((Short) head.get(head.lastKey())).shortValue();
+    }
+
+    /**
+     * @return  The number of formatting runs used. There will always be at
+     *          least one of font NO_FONT.
+     *
+     * @see #NO_FONT
+     */
+    public int numFormattingRuns()
+    {
+        return formattingRuns.size();
+    }
+
+    /**
+     * The index within the string to which the specified formatting run applies.
+     * @param index     the index of the formatting run
+     * @return  the index within the string.
+     */
+    public int getIndexOfFormattingRun(int index)
+    {
+        Map.Entry[] runs = (Map.Entry[]) formattingRuns.entrySet().toArray(new Map.Entry[formattingRuns.size()] );
+        return ((Integer)runs[index].getKey()).intValue();
+    }
+
+    /**
+     * Gets the font used in a particular formatting run.
+     *
+     * @param index     the index of the formatting run
+     * @return  the font number used.
+     */
+    public short getFontOfFormattingRun(int index)
+    {
+        Map.Entry[] runs = (Map.Entry[]) formattingRuns.entrySet().toArray(new Map.Entry[formattingRuns.size()] );
+        return ((Short)(runs[index].getValue())).shortValue();
+    }
+
+    /**
+     * Compares one rich text string to another.
+     */
+    public int compareTo( Object o )
+    {
+        return 0; // todo
+    }
+
+    /**
+     * @return  the plain text representation of this string.
+     */
+    public String toString()
+    {
+        return string;
+    }
+
+    /**
+     * Applies the specified font to the entire string.
+     *
+     * @param fontIndex  the font to apply.
+     */
+    public void applyFont( short fontIndex )
+    {
+        applyFont(0, string.length(), fontIndex);
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShape.java
new file mode 100644 (file)
index 0000000..61620f2
--- /dev/null
@@ -0,0 +1,195 @@
+package org.apache.poi.hssf.usermodel;
+
+/**
+ * An abstract shape.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public abstract class HSSFShape
+{
+    public static final int LINEWIDTH_ONE_PT = 12700;
+    public static final int LINEWIDTH_DEFAULT = 9525;
+
+    public static final int LINESTYLE_SOLID = 0;              // Solid (continuous) pen
+    public static final int LINESTYLE_DASHSYS = 1;            // PS_DASH system   dash style
+    public static final int LINESTYLE_DOTSYS = 2;             // PS_DOT system   dash style
+    public static final int LINESTYLE_DASHDOTSYS = 3;         // PS_DASHDOT system dash style
+    public static final int LINESTYLE_DASHDOTDOTSYS = 4;      // PS_DASHDOTDOT system dash style
+    public static final int LINESTYLE_DOTGEL = 5;             // square dot style
+    public static final int LINESTYLE_DASHGEL = 6;            // dash style
+    public static final int LINESTYLE_LONGDASHGEL = 7;        // long dash style
+    public static final int LINESTYLE_DASHDOTGEL = 8;         // dash short dash
+    public static final int LINESTYLE_LONGDASHDOTGEL = 9;     // long dash short dash
+    public static final int LINESTYLE_LONGDASHDOTDOTGEL = 10; // long dash short dash short dash
+    public static final int LINESTYLE_NONE = -1;
+
+    HSSFShape parent;
+    HSSFAnchor anchor;
+    int lineStyleColor = 0x08000040;
+    int fillColor = 0x08000009;
+    int lineWidth = LINEWIDTH_DEFAULT;    // 12700 = 1pt
+    int lineStyle = LINESTYLE_SOLID;
+    boolean noFill = false;
+
+    /**
+     * Create a new shape with the specified parent and anchor.
+     */
+    HSSFShape( HSSFShape parent, HSSFAnchor anchor )
+    {
+        this.parent = parent;
+        this.anchor = anchor;
+    }
+
+    /**
+     * Gets the parent shape.
+     */
+    public HSSFShape getParent()
+    {
+        return parent;
+    }
+
+    /**
+     * @return  the anchor that is used by this shape.
+     */
+    public HSSFAnchor getAnchor()
+    {
+        return anchor;
+    }
+
+    /**
+     * Sets a particular anchor.  A top-level shape must have an anchor of
+     * HSSFClientAnchor.  A child anchor must have an anchor of HSSFChildAnchor
+     *
+     * @param anchor    the anchor to use.
+     * @throws IllegalArgumentException     when the wrong anchor is used for
+     *                                      this particular shape.
+     *
+     * @see HSSFChildAnchor
+     * @see HSSFClientAnchor
+     */
+    public void setAnchor( HSSFAnchor anchor )
+    {
+        if ( parent == null )
+        {
+            if ( anchor instanceof HSSFChildAnchor )
+                throw new IllegalArgumentException( "Must use client anchors for shapes directly attached to sheet." );
+        }
+        else
+        {
+            if ( anchor instanceof HSSFClientAnchor )
+                throw new IllegalArgumentException( "Must use child anchors for shapes attached to groups." );
+        }
+
+        this.anchor = anchor;
+    }
+
+    /**
+     * The color applied to the lines of this shape.
+     */
+    public int getLineStyleColor()
+    {
+        return lineStyleColor;
+    }
+
+    /**
+     * The color applied to the lines of this shape.
+     */
+    public void setLineStyleColor( int lineStyleColor )
+    {
+        this.lineStyleColor = lineStyleColor;
+    }
+
+    /**
+     * The color applied to the lines of this shape.
+     */
+    public void setLineStyleColor( int red, int green, int blue )
+    {
+        this.lineStyleColor = ((blue) << 16) | ((green) << 8) | red;
+    }
+
+    /**
+     * The color used to fill this shape.
+     */
+    public int getFillColor()
+    {
+        return fillColor;
+    }
+
+    /**
+     * The color used to fill this shape.
+     */
+    public void setFillColor( int fillColor )
+    {
+        this.fillColor = fillColor;
+    }
+
+    /**
+     * The color used to fill this shape.
+     */
+    public void setFillColor( int red, int green, int blue )
+    {
+        this.fillColor = ((blue) << 16) | ((green) << 8) | red;
+    }
+
+    /**
+     * @return  returns with width of the line in EMUs.  12700 = 1 pt.
+     */
+    public int getLineWidth()
+    {
+        return lineWidth;
+    }
+
+    /**
+     * Sets the width of the line.  12700 = 1 pt.
+     *
+     * @param lineWidth width in EMU's.  12700EMU's = 1 pt
+     *
+     * @see HSSFShape#LINEWIDTH_ONE_PT
+     */
+    public void setLineWidth( int lineWidth )
+    {
+        this.lineWidth = lineWidth;
+    }
+
+    /**
+     * @return One of the constants in LINESTYLE_*
+     */
+    public int getLineStyle()
+    {
+        return lineStyle;
+    }
+
+    /**
+     * Sets the line style.
+     *
+     * @param lineStyle     One of the constants in LINESTYLE_*
+     */
+    public void setLineStyle( int lineStyle )
+    {
+        this.lineStyle = lineStyle;
+    }
+
+    /**
+     * @return  true if this shape is not filled with a color.
+     */
+    public boolean isNoFill()
+    {
+        return noFill;
+    }
+
+    /**
+     * Sets whether this shape is filled or transparent.
+     */
+    public void setNoFill( boolean noFill )
+    {
+        this.noFill = noFill;
+    }
+
+    /**
+     * Count of all children and their childrens children.
+     */
+    public int countOfAllChildren()
+    {
+        return 1;
+    }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeContainer.java
new file mode 100644 (file)
index 0000000..f641fe9
--- /dev/null
@@ -0,0 +1,17 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.List;
+
+/**
+ * An interface that indicates whether a class can contain children.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public interface HSSFShapeContainer
+{
+    /**
+     * @return  Any children contained by this shape.
+     */
+    List getChildren();
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java b/src/java/org/apache/poi/hssf/usermodel/HSSFShapeGroup.java
new file mode 100644 (file)
index 0000000..c33c8c6
--- /dev/null
@@ -0,0 +1,148 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * A shape group may contain other shapes.  It was no actual form on the
+ * sheet.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFShapeGroup
+        extends HSSFShape
+        implements HSSFShapeContainer
+{
+    List shapes = new ArrayList();
+    int x1 = 0;
+    int y1  = 0 ;
+    int x2 = 1023;
+    int y2 = 255;
+
+
+    public HSSFShapeGroup( HSSFShape parent, HSSFAnchor anchor )
+    {
+        super( parent, anchor );
+    }
+
+    /**
+     * Create another group under this group.
+     * @param anchor    the position of the new group.
+     * @return  the group
+     */
+    public HSSFShapeGroup createGroup(HSSFChildAnchor anchor)
+    {
+        HSSFShapeGroup group = new HSSFShapeGroup(this, anchor);
+        group.anchor = anchor;
+        shapes.add(group);
+        return group;
+    }
+
+    /**
+     * Create a new simple shape under this group.
+     * @param anchor    the position of the shape.
+     * @return  the shape
+     */
+    public HSSFSimpleShape createShape(HSSFChildAnchor anchor)
+    {
+        HSSFSimpleShape shape = new HSSFSimpleShape(this, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Create a new textbox under this group.
+     * @param anchor    the position of the shape.
+     * @return  the textbox
+     */
+    public HSSFTextbox createTextbox(HSSFChildAnchor anchor)
+    {
+        HSSFTextbox shape = new HSSFTextbox(this, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Creates a polygon
+     *
+     * @param anchor    the client anchor describes how this group is attached
+     *                  to the sheet.
+     * @return  the newly created shape.
+     */
+    public HSSFPolygon createPolygon(HSSFChildAnchor anchor)
+    {
+        HSSFPolygon shape = new HSSFPolygon(this, anchor);
+        shape.anchor = anchor;
+        shapes.add(shape);
+        return shape;
+    }
+
+    /**
+     * Return all children contained by this shape.
+     */
+    public List getChildren()
+    {
+        return shapes;
+    }
+
+    /**
+     * Sets the coordinate space of this group.  All children are contrained
+     * to these coordinates.
+     */
+    public void setCoordinates( int x1, int y1, int x2, int y2 )
+    {
+        this.x1 = x1;
+        this.y1 = y1;
+        this.x2 = x2;
+        this.y2 = y2;
+    }
+
+    /**
+     * The top left x coordinate of this group.
+     */
+    public int getX1()
+    {
+        return x1;
+    }
+
+    /**
+     * The top left y coordinate of this group.
+     */
+    public int getY1()
+    {
+        return y1;
+    }
+
+    /**
+     * The bottom right x coordinate of this group.
+     */
+    public int getX2()
+    {
+        return x2;
+    }
+
+    /**
+     * The bottom right y coordinate of this group.
+     */
+    public int getY2()
+    {
+        return y2;
+    }
+
+    /**
+     * Count of all children and their childrens children.
+     */
+    public int countOfAllChildren()
+    {
+        int count = shapes.size();
+        for ( Iterator iterator = shapes.iterator(); iterator.hasNext(); )
+        {
+            HSSFShape shape = (HSSFShape) iterator.next();
+            count += shape.countOfAllChildren();
+        }
+        return count;
+    }
+}
index f8c314b80809ab27dcf7d8ddda78eedefc83812f..da8c606cf6801a327876bba6366f68a483f846f3 100644 (file)
  */
 package org.apache.poi.hssf.usermodel;
 
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.TreeMap;
-
+import org.apache.poi.ddf.EscherRecord;
 import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.CellValueRecordInterface;
-import org.apache.poi.hssf.record.HCenterRecord;
-import org.apache.poi.hssf.record.PageBreakRecord;
-import org.apache.poi.hssf.record.Record;
-import org.apache.poi.hssf.record.RowRecord;
-import org.apache.poi.hssf.record.SCLRecord;
-import org.apache.poi.hssf.record.VCenterRecord;
-import org.apache.poi.hssf.record.WSBoolRecord;
-import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.util.Region;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeMap;
+
 /**
  * High level representation of a worksheet.
  * @author  Andrew C. Oliver (acoliver at apache dot org)
@@ -874,13 +868,13 @@ public class HSSFSheet
     {
         getSheet().setMargin( margin, size );
     }
-    
+
        /**
         * Answer whether protection is enabled or disabled
         * @return true => protection enabled; false => protection disabled
         */
        public boolean getProtect() {
-               return getSheet().getProtect().getProtect();            
+               return getSheet().getProtect().getProtect();
        }
 
        /**
@@ -888,7 +882,7 @@ public class HSSFSheet
         * @param protect true => protection enabled; false => protection disabled
         */
        public void setProtect(boolean protect) {
-               getSheet().getProtect().setProtect(protect);            
+               getSheet().getProtect().setProtect(protect);
        }
 
     /**
@@ -926,34 +920,34 @@ public class HSSFSheet
                //move merged regions completely if they fall within the new region boundaries when they are shifted
                for (int i = 0; i < this.getNumMergedRegions(); i++) {
                         Region merged = this.getMergedRegionAt(i);
-                       
+
                         boolean inStart = (merged.getRowFrom() >= startRow || merged.getRowTo() >= startRow);
                         boolean inEnd =  (merged.getRowTo() <= endRow || merged.getRowFrom() <= endRow);
-                       
+
                         //dont check if it's not within the shifted area
                         if (! (inStart && inEnd)) continue;
-                       
-                        //only shift if the region outside the shifted rows is not merged too                                  
+
+                        //only shift if the region outside the shifted rows is not merged too
                         if (!merged.contains(startRow-1, (short)0) && !merged.contains(endRow+1, (short)0)){
-                                merged.setRowFrom(merged.getRowFrom()+n);                                      
+                                merged.setRowFrom(merged.getRowFrom()+n);
                                 merged.setRowTo(merged.getRowTo()+n);
                                 //have to remove/add it back
                                 shiftedRegions.add(merged);
                                 this.removeMergedRegion(i);
                                 i = i -1; // we have to back up now since we removed one
-                                       
+
                         }
-                       
+
                }
-               
+
                //readd so it doesn't get shifted again
                Iterator iterator = shiftedRegions.iterator();
                while (iterator.hasNext()) {
                        Region region = (Region)iterator.next();
-                       
+
                        this.addMergedRegion(region);
                }
-               
+
        }
 
     /**
@@ -978,7 +972,7 @@ public class HSSFSheet
      * Shifts rows between startRow and endRow n number of rows.
      * If you use a negative number, it will shift rows up.
      * Code ensures that rows don't wrap around
-     * 
+     *
      * <p>
      * Additionally shifts merged regions that are completely defined in these
      * rows (ie. merged 2 cells on a row to be shifted).
@@ -1006,19 +1000,19 @@ public class HSSFSheet
             inc = -1;
         }
 
-                       shiftMerged(startRow, endRow, n, true);        
-                       sheet.shiftRowBreaks(startRow, endRow, n);
+        shiftMerged(startRow, endRow, n, true);
+        sheet.shiftRowBreaks(startRow, endRow, n);
                        
         for ( int rowNum = s; rowNum >= startRow && rowNum <= endRow && rowNum >= 0 && rowNum < 65536; rowNum += inc )
         {
             HSSFRow row = getRow( rowNum );
-            HSSFRow row2Replace = getRow( rowNum + n );            
+            HSSFRow row2Replace = getRow( rowNum + n );
             if ( row2Replace == null )
                 row2Replace = createRow( rowNum + n );
-           
+
             HSSFCell cell;
 
-                       
+
 
 
            // Removes the cells before over writting them.
@@ -1033,10 +1027,10 @@ public class HSSFSheet
                if (copyRowHeight) {
                    row2Replace.setHeight(row.getHeight());
                }
-               
+
                if (resetOriginalRowHeight) {
                    row.setHeight((short)0xff);
-               } 
+               }
            }
             for ( short col = row.getFirstCellNum(); col <= row.getLastCellNum(); col++ )
             {
@@ -1255,4 +1249,46 @@ public class HSSFSheet
        if (column > 255) throw new IllegalArgumentException("Maximum column number is 255");
        if (column < 0) throw new IllegalArgumentException("Minimum column number is 0");
     }
+
+    /**
+     * Aggregates the drawing records and dumps the escher record hierarchy
+     * to the standard output.
+     */
+    public void dumpDrawingRecords()
+    {
+        sheet.aggregateDrawingRecords(book.getDrawingManager());
+
+        EscherAggregate r = (EscherAggregate) getSheet().findFirstRecordBySid(EscherAggregate.sid);
+        List escherRecords = r.getEscherRecords();
+        for ( Iterator iterator = escherRecords.iterator(); iterator.hasNext(); )
+        {
+            EscherRecord escherRecord = (EscherRecord) iterator.next();
+            PrintWriter w = new PrintWriter(System.out);
+            escherRecord.display(w, 0);
+            w.close();
+        }
+    }
+
+    /**
+     * Creates the toplevel drawing patriarch.  This will have the effect of
+     * removing any existing drawings on this sheet.
+     *
+     * @return  The new patriarch.
+     */
+    public HSSFPatriarch createDrawingPatriarch()
+    {
+        // Create the drawing group if it doesn't already exist.
+        book.createDrawingGroup();
+
+        sheet.aggregateDrawingRecords(book.getDrawingManager());
+        EscherAggregate agg = (EscherAggregate) sheet.findFirstRecordBySid(EscherAggregate.sid);
+        HSSFPatriarch patriarch = new HSSFPatriarch(this);
+        agg.clear();     // Initially the behaviour will be to clear out any existing shapes in the sheet when
+                         // creating a new patriarch.
+        agg.setPatriarch(patriarch);
+        return patriarch;
+    }
+
+
+
 }
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSimpleShape.java
new file mode 100644 (file)
index 0000000..c90fe6b
--- /dev/null
@@ -0,0 +1,64 @@
+package org.apache.poi.hssf.usermodel;
+
+/**
+ * Represents a simple shape such as a line, rectangle or oval.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFSimpleShape
+    extends HSSFShape
+{
+    // The commented out ones haven't been tested yet or aren't supported
+    // by HSSFSimpleShape.
+
+    public final static short       OBJECT_TYPE_LINE               = 1;
+    public final static short       OBJECT_TYPE_RECTANGLE          = 2;
+    public final static short       OBJECT_TYPE_OVAL               = 3;
+//    public final static short       OBJECT_TYPE_ARC                = 4;
+//    public final static short       OBJECT_TYPE_CHART              = 5;
+//    public final static short       OBJECT_TYPE_TEXT               = 6;
+//    public final static short       OBJECT_TYPE_BUTTON             = 7;
+//    public final static short       OBJECT_TYPE_PICTURE            = 8;
+//    public final static short       OBJECT_TYPE_POLYGON            = 9;
+//    public final static short       OBJECT_TYPE_CHECKBOX           = 11;
+//    public final static short       OBJECT_TYPE_OPTION_BUTTON      = 12;
+//    public final static short       OBJECT_TYPE_EDIT_BOX           = 13;
+//    public final static short       OBJECT_TYPE_LABEL              = 14;
+//    public final static short       OBJECT_TYPE_DIALOG_BOX         = 15;
+//    public final static short       OBJECT_TYPE_SPINNER            = 16;
+//    public final static short       OBJECT_TYPE_SCROLL_BAR         = 17;
+//    public final static short       OBJECT_TYPE_LIST_BOX           = 18;
+//    public final static short       OBJECT_TYPE_GROUP_BOX          = 19;
+//    public final static short       OBJECT_TYPE_COMBO_BOX          = 20;
+//    public final static short       OBJECT_TYPE_COMMENT            = 25;
+//    public final static short       OBJECT_TYPE_MICROSOFT_OFFICE_DRAWING = 30;
+
+    int shapeType = OBJECT_TYPE_LINE;
+
+    HSSFSimpleShape( HSSFShape parent, HSSFAnchor anchor )
+    {
+        super( parent, anchor );
+    }
+
+    /**
+     * Gets the shape type.
+     * @return  One of the OBJECT_TYPE_* constants.
+     *
+     * @see #OBJECT_TYPE_LINE
+     * @see #OBJECT_TYPE_OVAL
+     * @see #OBJECT_TYPE_RECTANGLE
+     */
+    public int getShapeType() { return shapeType; }
+
+    /**
+     * Sets the shape types.
+     *
+     * @param shapeType One of the OBJECT_TYPE_* constants.
+     *
+     * @see #OBJECT_TYPE_LINE
+     * @see #OBJECT_TYPE_OVAL
+     * @see #OBJECT_TYPE_RECTANGLE
+     */
+    public void setShapeType( int shapeType ){ this.shapeType = shapeType; }
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java b/src/java/org/apache/poi/hssf/usermodel/HSSFTextbox.java
new file mode 100644 (file)
index 0000000..423e256
--- /dev/null
@@ -0,0 +1,107 @@
+package org.apache.poi.hssf.usermodel;
+
+/**
+ * A textbox is a shape that may hold a rich text string.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+public class HSSFTextbox
+        extends HSSFSimpleShape
+{
+    public final static short       OBJECT_TYPE_TEXT               = 6;
+
+    int marginLeft, marginRight, marginTop, marginBottom;
+
+    HSSFRichTextString string = new HSSFRichTextString("");
+
+    /**
+     * Construct a new textbox with the given parent and anchor.
+     * @param parent
+     * @param anchor  One of HSSFClientAnchor or HSSFChildAnchor
+     */
+    public HSSFTextbox( HSSFShape parent, HSSFAnchor anchor )
+    {
+        super( parent, anchor );
+        setShapeType(OBJECT_TYPE_TEXT);
+    }
+
+    /**
+     * @return  the rich text string for this textbox.
+     */
+    public HSSFRichTextString getString()
+    {
+        return string;
+    }
+
+    /**
+     * @param string    Sets the rich text string used by this object.
+     */
+    public void setString( HSSFRichTextString string )
+    {
+        this.string = string;
+    }
+
+    /**
+     * @return  Returns the left margin within the textbox.
+     */
+    public int getMarginLeft()
+    {
+        return marginLeft;
+    }
+
+    /**
+     * Sets the left margin within the textbox.
+     */
+    public void setMarginLeft( int marginLeft )
+    {
+        this.marginLeft = marginLeft;
+    }
+
+    /**
+     * @return    returns the right margin within the textbox.
+     */
+    public int getMarginRight()
+    {
+        return marginRight;
+    }
+
+    /**
+     * Sets the right margin within the textbox.
+     */
+    public void setMarginRight( int marginRight )
+    {
+        this.marginRight = marginRight;
+    }
+
+    /**
+     * @return  returns the top margin within the textbox.
+     */
+    public int getMarginTop()
+    {
+        return marginTop;
+    }
+
+    /**
+     * Sets the top margin within the textbox.
+     */
+    public void setMarginTop( int marginTop )
+    {
+        this.marginTop = marginTop;
+    }
+
+    /**
+     * Gets the bottom margin within the textbox.
+     */
+    public int getMarginBottom()
+    {
+        return marginBottom;
+    }
+
+    /**
+     * Sets the bottom margin within the textbox.
+     */
+    public void setMarginBottom( int marginBottom )
+    {
+        this.marginBottom = marginBottom;
+    }
+}
index c1bfbd318214b4b39346af99375d435ca295bc3a..4ea6e683c76547159c33df51c8d31e1d9ebe4327 100644 (file)
@@ -71,14 +71,7 @@ import java.util.Stack;
 import org.apache.poi.hssf.eventmodel.EventRecordFactory;
 import org.apache.poi.hssf.model.Sheet;
 import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.BackupRecord;
-import org.apache.poi.hssf.record.ExtendedFormatRecord;
-import org.apache.poi.hssf.record.FontRecord;
-import org.apache.poi.hssf.record.NameRecord;
-import org.apache.poi.hssf.record.RecordFactory;
-import org.apache.poi.hssf.record.SSTRecord;
-import org.apache.poi.hssf.record.UnknownRecord;
-import org.apache.poi.hssf.record.WindowTwoRecord;
+import org.apache.poi.hssf.record.*;
 import org.apache.poi.hssf.record.formula.Area3DPtg;
 import org.apache.poi.hssf.record.formula.MemFuncPtg;
 import org.apache.poi.hssf.record.formula.UnionPtg;
@@ -90,6 +83,8 @@ import org.apache.poi.poifs.filesystem.Entry;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
+import org.apache.poi.util.HexDump;
+import org.apache.poi.ddf.*;
 
 /**
  * High level representation of a workbook.  This is the first object most users
@@ -129,16 +124,16 @@ public class HSSFWorkbook
      */
 
     private ArrayList sheets;
-    
+
     /**
      * this holds the HSSFName objects attached to this workbook
      */
 
     private ArrayList names;
+
     /**
      * holds whether or not to preserve other nodes in the POIFS.  Used
-     * for macros and embedded objects. 
+     * for macros and embedded objects.
      */
     private boolean   preserveNodes;
 
@@ -155,7 +150,7 @@ public class HSSFWorkbook
      * someplace else.
      */
     private HSSFDataFormat formatter;
-    
+
     private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
 
     /**
@@ -179,7 +174,7 @@ public class HSSFWorkbook
      * low level models.  If you're reading in a workbook...start here.
      *
      * @param fs the POI filesystem that contains the Workbook stream.
-     * @param preserveNodes whether to preseve other nodes, such as 
+     * @param preserveNodes whether to preseve other nodes, such as
      *        macros.  This takes more memory, so only say yes if you
      *        need to.
      * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
@@ -190,20 +185,20 @@ public class HSSFWorkbook
             throws IOException
     {
         this.preserveNodes = preserveNodes;
-     
+
         if (preserveNodes) {
-           this.poifs = fs; 
+           this.poifs = fs;
         }
 
         sheets = new ArrayList(INITIAL_CAPACITY);
         names  = new ArrayList(INITIAL_CAPACITY);
-        
+
         InputStream stream = fs.createDocumentInputStream("Workbook");
-        
+
         EventRecordFactory factory = new EventRecordFactory();
-       
-        
-        
+
+
+
         List records = RecordFactory.createRecords(stream);
 
         workbook = Workbook.createWorkbook(records);
@@ -224,7 +219,7 @@ public class HSSFWorkbook
 
             // workbook.setSheetName(sheets.size() -1, "Sheet"+sheets.size());
         }
-        
+
         for (int i = 0 ; i < workbook.getNumNames() ; ++i){
             HSSFName name = new HSSFName(workbook, workbook.getNameRecord(i));
             names.add(name);
@@ -240,7 +235,7 @@ public class HSSFWorkbook
      * inputstream.
      *
      * @param s  the POI filesystem that contains the Workbook stream.
-     * @param preserveNodes whether to preseve other nodes, such as 
+     * @param preserveNodes whether to preseve other nodes, such as
      *        macros.  This takes more memory, so only say yes if you
      *        need to.
      * @see org.apache.poi.poifs.filesystem.POIFSFileSystem
@@ -264,22 +259,22 @@ public class HSSFWorkbook
 
         // none currently
     }
-    
+
     /**
      * sets the order of appearance for a given sheet.
      *
      * @param sheetname the name of the sheet to reorder
      * @param pos the position that we want to insert the sheet into (0 based)
      */
-    
+
     public void setSheetOrder(String sheetname, int pos ) {
         workbook.setSheetOrder(sheetname, pos);
     }
-    
+
     public final static byte ENCODING_COMPRESSED_UNICODE = 0;
     public final static byte ENCODING_UTF_16             = 1;
-    
-     
+
+
     /**
      * set the sheet name. 
      * Will throw IllegalArgumentException if the name is greater than 31 chars
@@ -299,17 +294,17 @@ public class HSSFWorkbook
         {
             throw new RuntimeException("Sheet out of bounds");
         }
-        
+
         switch ( encoding ) {
         case ENCODING_COMPRESSED_UNICODE:
         case ENCODING_UTF_16:
             break;
-            
+
         default:
             // TODO java.io.UnsupportedEncodingException
             throw new RuntimeException( "Unsupported encoding" );
         }
-        
+
         workbook.setSheetName( sheet, name, encoding );
     }
 
@@ -337,14 +332,14 @@ public class HSSFWorkbook
     /** Returns the index of the sheet by his name
      * @param name the sheet name
      * @return index of the sheet (0 based)
-     */    
+     */
     public int getSheetIndex(String name)
     {
         int retval = workbook.getSheetIndex(name);
-        
+
         return retval;
     }
-    
+
     /**
      * create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns
      * the high level representation.  Use this to create new sheets.
@@ -561,7 +556,7 @@ public class HSSFWorkbook
             //does a lot of the house keeping for builtin records, like setting lengths to zero etc
             isNewRecord = true;
         }
-        
+
         short definitionTextLength = settingRowAndColumn ? (short)0x001a : (short)0x000b;
         nameRecord.setDefinitionTextLength(definitionTextLength);
 
@@ -663,6 +658,40 @@ public class HSSFWorkbook
         return retval;
     }
 
+    /**
+     * Finds a font that matches the one with the supplied attributes
+     */
+    public HSSFFont findFont(short boldWeight, short color, short fontHeight,
+                             String name, boolean italic, boolean strikeout,
+                             short typeOffset, byte underline)
+    {
+//        System.out.println( boldWeight + ", " + color + ", " + fontHeight + ", " + name + ", " + italic + ", " + strikeout + ", " + typeOffset + ", " + underline );
+        for (short i = 0; i < workbook.getNumberOfFontRecords(); i++)
+        {
+            if (i == 4)
+                continue;
+
+            FontRecord font = workbook.getFontRecordAt(i);
+            HSSFFont hssfFont = new HSSFFont(i, font);
+//            System.out.println( hssfFont.getBoldweight() + ", " + hssfFont.getColor() + ", " + hssfFont.getFontHeight() + ", " + hssfFont.getFontName() + ", " + hssfFont.getItalic() + ", " + hssfFont.getStrikeout() + ", " + hssfFont.getTypeOffset() + ", " + hssfFont.getUnderline() );
+            if (hssfFont.getBoldweight() == boldWeight
+                    && hssfFont.getColor() == color
+                    && hssfFont.getFontHeight() == fontHeight
+                    && hssfFont.getFontName().equals(name)
+                    && hssfFont.getItalic() == italic
+                    && hssfFont.getStrikeout() == strikeout
+                    && hssfFont.getTypeOffset() == typeOffset
+                    && hssfFont.getUnderline() == underline)
+            {
+//                System.out.println( "Found font" );
+                return hssfFont;
+            }
+        }
+
+//        System.out.println( "No font found" );
+        return null;
+    }
+
     /**
      * get the number of fonts in the font table
      * @return number of fonts
@@ -741,10 +770,10 @@ public class HSSFWorkbook
     {
         byte[] bytes = getBytes();
         POIFSFileSystem fs = new POIFSFileSystem();
-      
+
         fs.createDocument(new ByteArrayInputStream(bytes), "Workbook");
 
-        if (preserveNodes) { 
+        if (preserveNodes) {
             List excepts = new ArrayList(1);
             excepts.add("Workbook");
             copyNodes(this.poifs,fs,excepts);
@@ -768,6 +797,12 @@ public class HSSFWorkbook
     public byte[] getBytes()
     {
         log.log(DEBUG, "HSSFWorkbook.getBytes()");
+
+        // before getting the workbook size we must tell the sheets that
+        // serialization is about to occur.
+        for (int k = 0; k < sheets.size(); k++)
+            ((HSSFSheet) sheets.get(k)).getSheet().preSerialize();
+
         int wbsize = workbook.getSize();
 
         // log.debug("REMOVEME: old sizing method "+workbook.serialize().length);
@@ -777,10 +812,10 @@ public class HSSFWorkbook
         for (int k = 0; k < sheets.size(); k++)
         {
             workbook.setSheetBof(k, totalsize);
-
-            // sheetbytes.add((( HSSFSheet ) sheets.get(k)).getSheet().getSize());
             totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
         }
+
+
 /*        if (totalsize < 4096)
         {
             totalsize = 4096;
@@ -818,58 +853,58 @@ public class HSSFWorkbook
     {
         return workbook;
     }
-    
+
     /** gets the total number of named ranges in the workboko
      * @return number of named ranges
-     */    
+     */
     public int getNumberOfNames(){
         int result = names.size();
         return result;
     }
-    
+
     /** gets the Named range
      * @param index position of the named range
      * @return named range high level
-     */    
+     */
     public HSSFName getNameAt(int index){
         HSSFName result = (HSSFName) names.get(index);
-        
+
         return result;
     }
-    
+
     /** gets the named range name
      * @param index the named range index (0 based)
      * @return named range name
-     */    
+     */
     public String getNameName(int index){
         String result = getNameAt(index).getNameName();
-                
+
         return result;
     }
-    
+
        /**
         * Sets the printarea for the sheet provided
         * <p>
         * i.e. Reference = $A$1:$B$2
         * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
-        * @param reference Valid name Reference for the Print Area 
+        * @param reference Valid name Reference for the Print Area
         */
        public void setPrintArea(int sheetIndex, String reference)
        {
                NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
-               
+
 
                if (name == null)
                        name = workbook.createBuiltInName(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
        //adding one here because 0 indicates a global named region; doesnt make sense for print areas
-       
+
            short externSheetIndex = getWorkbook().checkExternSheet(sheetIndex);
-               name.setExternSheetNumber(externSheetIndex);       
+               name.setExternSheetNumber(externSheetIndex);
                name.setAreaReference(reference);
-       
-               
+
+
        }
-       
+
        /**
         * For the Convenience of Java Programmers maintaining pointers.
         * @see setPrintArea(int, String)
@@ -881,57 +916,57 @@ public class HSSFWorkbook
         */
        public void setPrintArea(int sheetIndex, int startColumn, int endColumn,
                                                          int startRow, int endRow) {
-                                                               
-               //using absolute references because they dont get copied and pasted anyway                                                              
+
+               //using absolute references because they dont get copied and pasted anyway
                CellReference cell = new CellReference(startRow, startColumn, true, true);
                String reference = cell.toString();
-               
+
                cell = new CellReference(endRow, endColumn, true, true);
                reference = reference+":"+cell.toString();
-               
-               setPrintArea(sheetIndex, reference);                                                            
+
+               setPrintArea(sheetIndex, reference);
        }
-                                                         
-           
+
+
        /**
         * Retrieves the reference for the printarea of the specified sheet, the sheet name is appended to the reference even if it was not specified.
-        * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java) 
+        * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
         * @return String Null if no print area has been defined
-        */         
+        */
        public String getPrintArea(int sheetIndex)
        {
-               NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);               
+               NameRecord name = workbook.getSpecificBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
                if (name == null) return null;
                //adding one here because 0 indicates a global named region; doesnt make sense for print areas
-   
+
                return name.getAreaReference(workbook);
-       }    
-    
+       }
+
     /**
      * Delete the printarea for the sheet specified
      * @param sheetIndex Zero-based sheet index (0 = First Sheet)
      */
     public void removePrintArea(int sheetIndex) {
-       getWorkbook().removeBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1); 
+       getWorkbook().removeBuiltinRecord(NameRecord.BUILTIN_PRINT_AREA, sheetIndex+1);
     }
-    
+
     /** creates a new named range and add it to the model
      * @return named range high level
-     */    
+     */
     public HSSFName createName(){
         NameRecord nameRecord = workbook.createName();
-        
+
         HSSFName newName = new HSSFName(workbook, nameRecord);
-        
+
         names.add(newName);
-        
-        return newName; 
+
+        return newName;
     }
-    
+
     /** gets the named range index by his name
      * @param name named range name
-     * @return named range index 
-     */    
+     * @return named range index
+     */
     public int getNameIndex(String name)
     {
         int retval = -1;
@@ -952,10 +987,10 @@ public class HSSFWorkbook
 
     /** remove the named range by his index
      * @param index named range index (0 based)
-     */    
+     */
     public void removeName(int index){
         names.remove(index);
-        workbook.removeName(index);        
+        workbook.removeName(index);
     }
 
     /**
@@ -969,29 +1004,29 @@ public class HSSFWorkbook
            formatter = new HSSFDataFormat(workbook);
        return formatter;
     }
-       
+
     /** remove the named range by his name
      * @param name named range name
-     */    
+     */
     public void removeName(String name){
         int index = getNameIndex(name);
-        
-        removeName(index);          
-        
+
+        removeName(index);
+
     }
 
     public HSSFPalette getCustomPalette()
     {
         return new HSSFPalette(workbook.getCustomPalette());
     }
-    
+
    /**
     * Copies nodes from one POIFS to the other minus the excepts
     * @param source is the source POIFS to copy from
-    * @param target is the target POIFS to copy to 
-    * @param excepts is a list of Strings specifying what nodes NOT to copy 
+    * @param target is the target POIFS to copy to
+    * @param excepts is a list of Strings specifying what nodes NOT to copy
     */
-   private void copyNodes(POIFSFileSystem source, POIFSFileSystem target, 
+   private void copyNodes(POIFSFileSystem source, POIFSFileSystem target,
                           List excepts) throws IOException {
       //System.err.println("CopyNodes called");
 
@@ -999,13 +1034,13 @@ public class HSSFWorkbook
       DirectoryEntry newRoot = target.getRoot();
 
       Iterator entries = root.getEntries();
-       
+
       while (entries.hasNext()) {
          Entry entry = (Entry)entries.next();
          if (!isInList(entry.getName(), excepts)) {
              copyNodeRecursively(entry,newRoot);
          }
-      } 
+      }
    }
 
    private boolean isInList(String entry, List list) {
@@ -1017,18 +1052,18 @@ public class HSSFWorkbook
        return false;
    }
 
-   private void copyNodeRecursively(Entry entry, DirectoryEntry target) 
+   private void copyNodeRecursively(Entry entry, DirectoryEntry target)
    throws IOException {
        //System.err.println("copyNodeRecursively called with "+entry.getName()+
        //                   ","+target.getName());
-       DirectoryEntry newTarget = null; 
+       DirectoryEntry newTarget = null;
        if (entry.isDirectoryEntry()) {
            newTarget = target.createDirectory(entry.getName());
            Iterator entries = ((DirectoryEntry)entry).getEntries();
 
            while (entries.hasNext()) {
               copyNodeRecursively((Entry)entries.next(),newTarget);
-           } 
+           }
        } else {
          DocumentEntry dentry = (DocumentEntry)entry;
          DocumentInputStream dstream = new DocumentInputStream(dentry);
@@ -1037,6 +1072,7 @@ public class HSSFWorkbook
        }
    }
 
+    /** Test only. Do not use */
     public void insertChartRecord()
     {
         int loc = workbook.findFirstRecordLocBySid(SSTRecord.sid);
diff --git a/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java b/src/java/org/apache/poi/hssf/usermodel/StaticFontMetrics.java
new file mode 100644 (file)
index 0000000..1c7b330
--- /dev/null
@@ -0,0 +1,81 @@
+package org.apache.poi.hssf.usermodel;
+
+import java.util.*;
+import java.awt.*;
+import java.io.*;
+
+/**
+ * Allows the user to lookup the font metrics for a particular font without
+ * actually having the font on the system.  The font details are loaded
+ * as a resource from the POI jar file (or classpath) and should be contained
+ * in path "/font_metrics.properties".  The font widths are for a 10 point
+ * version of the font.  Use a multiplier for other sizes.
+ *
+ * @author Glen Stampoultzis (glens at apache.org)
+ */
+class StaticFontMetrics
+{
+    private static Properties fontMetricsProps;
+    private static Map fontDetailsMap = new HashMap();
+
+    /**
+     * Retrieves the fake font details for a given font.
+     * @param font  the font to lookup.
+     * @return  the fake font.
+     */
+    public static FontDetails getFontDetails(Font font)
+    {
+        if (fontMetricsProps == null)
+        {
+            InputStream metricsIn = null;
+            try
+            {
+                fontMetricsProps = new Properties();
+                if (System.getProperty("font.metrics.filename") != null)
+                {
+                    String filename = System.getProperty("font.metrics.filename");
+                    File file = new File(filename);
+                    if (!file.exists())
+                        throw new FileNotFoundException("font_metrics.properties not found at path " + file.getAbsolutePath());
+                    metricsIn = new FileInputStream(file);
+                }
+                else
+                {
+                    metricsIn = FontDetails.class.getResourceAsStream("/font_metrics.properties");
+                    if (metricsIn == null)
+                        throw new FileNotFoundException("font_metrics.properties not found in classpath");
+                }
+                fontMetricsProps.load(metricsIn);
+            }
+            catch ( IOException e )
+            {
+                throw new RuntimeException("Could not load font metrics: " + e.getMessage());
+            }
+            finally
+            {
+                if (metricsIn != null)
+                {
+                    try
+                    {
+                        metricsIn.close();
+                    }
+                    catch ( IOException ignore ) { }
+                }
+            }
+        }
+
+        String fontName = font.getName();
+
+        if (fontDetailsMap.get(fontName) == null)
+        {
+            FontDetails fontDetails = FontDetails.create(fontName, fontMetricsProps);
+            fontDetailsMap.put( fontName, fontDetails );
+            return fontDetails;
+        }
+        else
+        {
+            return (FontDetails) fontDetailsMap.get(fontName);
+        }
+
+    }
+}