diff options
author | Yegor Kozlov <yegor@apache.org> | 2008-01-04 14:19:14 +0000 |
---|---|---|
committer | Yegor Kozlov <yegor@apache.org> | 2008-01-04 14:19:14 +0000 |
commit | ce32b7c036323c2b722ee129ac8a428abd4fe5ce (patch) | |
tree | 9f1274454491f23d795137e6e6afcd7887f98f6e /src/scratchpad | |
parent | 329d1ae3307d1beccb50410dc960badd42ca5df0 (diff) | |
download | poi-REL_3_0_2_BETA2.tar.gz poi-REL_3_0_2_BETA2.zip |
merged TRUNK changes r608809 into REL_3_0_2_BETA2REL_3_0_2_BETA2
git-svn-id: https://svn.apache.org/repos/asf/poi/tags/REL_3_0_2_BETA2@608846 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/scratchpad')
36 files changed, 1152 insertions, 57 deletions
diff --git a/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java new file mode 100755 index 0000000000..25ff9ad017 --- /dev/null +++ b/src/scratchpad/examples/src/org/apache/poi/hslf/examples/TableDemo.java @@ -0,0 +1,127 @@ +
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hslf.examples;
+
+import org.apache.poi.hslf.usermodel.SlideShow;
+import org.apache.poi.hslf.usermodel.RichTextRun;
+import org.apache.poi.hslf.model.*;
+
+import java.awt.*;
+import java.io.FileOutputStream;
+
+/**
+ * Demonstrates how to create tables
+ *
+ * @author Yegor Kozlov
+ */
+public class TableDemo {
+
+ public static void main(String[] args) throws Exception {
+
+ //test data for the first taable
+ String[][] txt1 = {
+ {"INPUT FILE", "NUMBER OF RECORDS"},
+ {"Item File", "11,559"},
+ {"Vendor File", "502"},
+ {"Purchase History File - # of PO\u2019s\r(12/01/04 - 05/31/06)", "12,852"},
+ {"Purchase History File - # of PO Lines\r(12/01/04 - 05/31/06)", "53,523" },
+ {"Total PO History Spend", "$10,172,038"}
+ };
+
+ SlideShow ppt = new SlideShow();
+
+ Slide slide = ppt.createSlide();
+
+ //six rows, two columns
+ Table table1 = new Table(6, 2);
+ for (int i = 0; i < txt1.length; i++) {
+ for (int j = 0; j < txt1[i].length; j++) {
+ TableCell cell = table1.getCell(i, j);
+ cell.setText(txt1[i][j]);
+ RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
+ rt.setFontName("Arial");
+ rt.setFontSize(10);
+ if(i == 0){
+ cell.getFill().setForegroundColor(new Color(227, 227, 227));
+ } else {
+ rt.setBold(true);
+ }
+ cell.setVerticalAlignment(TextBox.AnchorMiddle);
+ cell.setHorizontalAlignment(TextBox.AlignCenter);
+ }
+ }
+
+ Line border1 = table1.createBorder();
+ border1.setLineColor(Color.black);
+ border1.setLineWidth(1.0);
+ table1.setAllBorders(border1);
+
+ table1.setColumnWidth(0, 300);
+ table1.setColumnWidth(1, 150);
+
+ slide.addShape(table1);
+ int pgWidth = ppt.getPageSize().width;
+ table1.moveTo((pgWidth - table1.getAnchor().width)/2, 100);
+
+ //test data for the second taable
+ String[][] txt2 = {
+ {"Data Source"},
+ {"CAS Internal Metrics - Item Master Summary\r" +
+ "CAS Internal Metrics - Vendor Summary\r" +
+ "CAS Internal Metrics - PO History Summary"}
+ };
+
+ //two rows, one column
+ Table table2 = new Table(2, 1);
+ for (int i = 0; i < txt2.length; i++) {
+ for (int j = 0; j < txt2[i].length; j++) {
+ TableCell cell = table2.getCell(i, j);
+ cell.setText(txt2[i][j]);
+ RichTextRun rt = cell.getTextRun().getRichTextRuns()[0];
+ rt.setFontSize(10);
+ rt.setFontName("Arial");
+ if(i == 0){
+ cell.getFill().setForegroundColor(new Color(0, 51, 102));
+ rt.setFontColor(Color.white);
+ rt.setBold(true);
+ rt.setFontSize(14);
+ cell.setHorizontalAlignment(TextBox.AlignCenter);
+ } else {
+ rt.setBullet(true);
+ rt.setFontSize(12);
+ cell.setHorizontalAlignment(TextBox.AlignLeft);
+ }
+ cell.setVerticalAlignment(TextBox.AnchorMiddle);
+ }
+ }
+ table2.setColumnWidth(0, 300);
+ table2.setRowHeight(0, 30);
+ table2.setRowHeight(1, 70);
+
+ Line border2 = table2.createBorder();
+ table2.setOutsideBorders(border2);
+
+ slide.addShape(table2);
+ table2.moveTo(200, 400);
+
+ FileOutputStream out = new FileOutputStream("hslf-table.ppt");
+ ppt.write(out);
+ out.close();
+
+ }
+}
diff --git a/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java b/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java index 5f7392739f..1c8d994bfe 100644 --- a/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java +++ b/src/scratchpad/examples/src/org/apache/poi/hssf/eventusermodel/examples/XLS2CSVmra.java @@ -283,7 +283,7 @@ public class XLS2CSVmra implements HSSFListener { format = format.replaceAll("\\\\-","-"); // Format as a date - Date d = HSSFDateUtil.getJavaDate(value); + Date d = HSSFDateUtil.getJavaDate(value, false); DateFormat df = new SimpleDateFormat(format); return df.format(d); } else { diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java index f0d85400be..7eae4edc4c 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Fill.java @@ -150,10 +150,12 @@ public class Fill { EscherOptRecord opt = (EscherOptRecord)Shape.getEscherChild(shape.getSpContainer(), EscherOptRecord.RECORD_ID); if (color == null) { Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, -1); + Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150010); } else { int rgb = new Color(color.getBlue(), color.getGreen(), color.getRed(), 0).getRGB(); Shape.setEscherProperty(opt, EscherProperties.FILL__FILLCOLOR, rgb); + Shape.setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150011); } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java index b1761b2d9a..d8ddc7d2f2 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java @@ -153,7 +153,7 @@ public abstract class Sheet { */ protected static void findTextRuns(Record[] records, Vector found) { // Look for a TextHeaderAtom - for (int i = 0; i < (records.length - 1); i++) { + for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) { if (records[i] instanceof TextHeaderAtom) { TextRun trun = null; TextHeaderAtom tha = (TextHeaderAtom) records[i]; @@ -179,7 +179,6 @@ public abstract class Sheet { // TextSpecInfoAtom - Safe to ignore } else { System.err.println("Found a TextHeaderAtom not followed by a TextBytesAtom or TextCharsAtom: Followed by " + records[i + 1].getRecordType()); - continue; } if (trun != null) { @@ -191,12 +190,14 @@ public abstract class Sheet { Record[] recs = new Record[lst.size()]; lst.toArray(recs); trun._records = recs; + trun.setIndex(slwtIndex); found.add(trun); i++; } else { // Not a valid one, so skip on to next and look again } + slwtIndex++; } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java index 2f634ccd17..1074916004 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/SimpleShape.java @@ -124,8 +124,10 @@ public class SimpleShape extends Shape { int rgb = p1.getPropertyValue(); if (rgb >= 0x8000000) { int idx = rgb % 0x8000000; - ColorSchemeAtom ca = getSheet().getColorScheme(); - if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx); + if(getSheet() != null) { + ColorSchemeAtom ca = getSheet().getColorScheme(); + if(idx >= 0 && idx <= 7) rgb = ca.getColor(idx); + } } Color tmp = new Color(rgb, true); clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); @@ -192,8 +194,10 @@ public class SimpleShape extends Shape { int rgb = p1.getPropertyValue(); if (rgb >= 0x8000000) { int idx = rgb % 0x8000000; - ColorSchemeAtom ca = getSheet().getColorScheme(); - rgb = ca.getColor(idx); + if(getSheet() != null) { + ColorSchemeAtom ca = getSheet().getColorScheme(); + rgb = ca.getColor(idx); + } } Color tmp = new Color(rgb, true); clr = new Color(tmp.getBlue(), tmp.getGreen(), tmp.getRed()); diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/Table.java b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java new file mode 100755 index 0000000000..a9f21b54f3 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/Table.java @@ -0,0 +1,291 @@ +
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.util.LittleEndian;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Iterator;
+import java.awt.*;
+
+/**
+ * Represents a table in a PowerPoint presentation
+ *
+ * @author Yegor Kozlov
+ */
+public class Table extends ShapeGroup {
+
+ protected static final int BORDER_TOP = 1;
+ protected static final int BORDER_RIGHT = 2;
+ protected static final int BORDER_BOTTOM = 3;
+ protected static final int BORDER_LEFT = 4;
+
+ protected static final int BORDERS_ALL = 5;
+ protected static final int BORDERS_OUTSIDE = 6;
+ protected static final int BORDERS_INSIDE = 7;
+ protected static final int BORDERS_NONE = 8;
+
+
+ protected TableCell[][] cells;
+
+ /**
+ * Create a new Table of the given number of rows and columns
+ *
+ * @param numrows the number of rows
+ * @param numcols the number of columns
+ */
+ public Table(int numrows, int numcols) {
+ super();
+
+ int x=0, y=0, tblWidth=0, tblHeight=0;
+ cells = new TableCell[numrows][numcols];
+ for (int i = 0; i < cells.length; i++) {
+ x = 0;
+ for (int j = 0; j < cells[i].length; j++) {
+ cells[i][j] = new TableCell(this);
+ Rectangle anchor = new Rectangle(x, y, TableCell.DEFAULT_WIDTH, TableCell.DEFAULT_HEIGHT);
+ cells[i][j].setAnchor(anchor);
+ x += TableCell.DEFAULT_WIDTH;
+ }
+ y += TableCell.DEFAULT_HEIGHT;
+ }
+ tblWidth = x;
+ tblHeight = y;
+ setAnchor(new Rectangle(0, 0, tblWidth, tblHeight));
+
+ EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
+ List lst = spCont.getChildRecords();
+ EscherOptRecord opt = new EscherOptRecord();
+ opt.setRecordId((short)0xF122);
+ opt.addEscherProperty(new EscherSimpleProperty((short)0x39F, 1));
+ EscherArrayProperty p = new EscherArrayProperty((short)0x43A0, false, null);
+ p.setSizeOfElements(0x0004);
+ p.setNumberOfElementsInArray(numrows);
+ p.setNumberOfElementsInMemory(numrows);
+ opt.addEscherProperty(p);
+ lst.add(lst.size()-1, opt);
+
+ }
+
+ /**
+ * Create a Table object and initilize it from the supplied Record container.
+ *
+ * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
+ * @param parent the parent of the shape
+ */
+ protected Table(EscherContainerRecord escherRecord, Shape parent) {
+ super(escherRecord, parent);
+ }
+
+ /**
+ * Gets a cell
+ *
+ * @param row the row index (0-based)
+ * @param col the column index (0-based)
+ * @return the cell
+ */
+ public TableCell getCell(int row, int col) {
+ return cells[row][col];
+ }
+
+ public int getNumberOfColumns() {
+ return cells[0].length;
+ }
+ public int getNumberOfRows() {
+ return cells.length;
+ }
+
+ protected void afterInsert(Sheet sh){
+ EscherContainerRecord spCont = (EscherContainerRecord) getSpContainer().getChild(0);
+ List lst = spCont.getChildRecords();
+ EscherOptRecord opt = (EscherOptRecord)lst.get(lst.size()-2);
+ EscherArrayProperty p = (EscherArrayProperty)opt.getEscherProperty(1);
+ for (int i = 0; i < cells.length; i++) {
+ TableCell cell = cells[i][0];
+ int rowHeight = cell.getAnchor().height*MASTER_DPI/POINT_DPI;
+ byte[] val = new byte[4];
+ LittleEndian.putInt(val, rowHeight);
+ p.setElement(i, val);
+ for (int j = 0; j < cells[i].length; j++) {
+ TableCell c = cells[i][j];
+ addShape(c);
+
+ Line bt = c.getBorderTop();
+ if(bt != null) addShape(bt);
+
+ Line br = c.getBorderRight();
+ if(br != null) addShape(br);
+
+ Line bb = c.getBorderBottom();
+ if(bb != null) addShape(bb);
+
+ Line bl = c.getBorderLeft();
+ if(bl != null) addShape(bl);
+
+ }
+ }
+
+ }
+
+ /**
+ * Sets the row height.
+ *
+ * @param row the row index (0-based)
+ * @param height the height to set (in pixels)
+ */
+ public void setRowHeight(int row, int height){
+ int currentHeight = cells[row][0].getAnchor().height;
+ int dy = height - currentHeight;
+
+ for (int i = row; i < cells.length; i++) {
+ for (int j = 0; j < cells[i].length; j++) {
+ Rectangle anchor = cells[i][j].getAnchor();
+ if(i == row) anchor.height = height;
+ else anchor.y += dy;
+ cells[i][j].setAnchor(anchor);
+ }
+ }
+ Rectangle tblanchor = getAnchor();
+ tblanchor.height += dy;
+ setAnchor(tblanchor);
+
+ }
+
+ /**
+ * Sets the column width.
+ *
+ * @param col the column index (0-based)
+ * @param width the width to set (in pixels)
+ */
+ public void setColumnWidth(int col, int width){
+ int currentWidth = cells[0][col].getAnchor().width;
+ int dx = width - currentWidth;
+ for (int i = 0; i < cells.length; i++) {
+ Rectangle anchor = cells[i][col].getAnchor();
+ anchor.width = width;
+ cells[i][col].setAnchor(anchor);
+
+ if(col < cells[i].length - 1) for (int j = col+1; j < cells[i].length; j++) {
+ anchor = cells[i][j].getAnchor();
+ anchor.x += dx;
+ cells[i][j].setAnchor(anchor);
+ }
+ }
+ Rectangle tblanchor = getAnchor();
+ tblanchor.width += dx;
+ setAnchor(tblanchor);
+ }
+
+ /**
+ * Format the table and apply the specified Line to all cell boundaries,
+ * both outside and inside
+ *
+ * @param line the border line
+ */
+ public void setAllBorders(Line line){
+ for (int i = 0; i < cells.length; i++) {
+ for (int j = 0; j < cells[i].length; j++) {
+ TableCell cell = cells[i][j];
+ cell.setBorderTop(cloneBorder(line));
+ cell.setBorderLeft(cloneBorder(line));
+ if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));
+ if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line));
+ }
+ }
+ }
+
+ /**
+ * Format the outside border using the specified Line object
+ *
+ * @param line the border line
+ */
+ public void setOutsideBorders(Line line){
+ for (int i = 0; i < cells.length; i++) {
+ for (int j = 0; j < cells[i].length; j++) {
+ TableCell cell = cells[i][j];
+
+ if(j == 0) cell.setBorderLeft(cloneBorder(line));
+ if(j == cells[i].length - 1) cell.setBorderRight(cloneBorder(line));
+ else {
+ cell.setBorderLeft(null);
+ cell.setBorderLeft(null);
+ }
+
+ if(i == 0) cell.setBorderTop(cloneBorder(line));
+ else if(i == cells.length - 1) cell.setBorderBottom(cloneBorder(line));
+ else {
+ cell.setBorderTop(null);
+ cell.setBorderBottom(null);
+ }
+ }
+ }
+ }
+
+ /**
+ * Format the inside border using the specified Line object
+ *
+ * @param line the border line
+ */
+ public void setInsideBorders(Line line){
+ for (int i = 0; i < cells.length; i++) {
+ for (int j = 0; j < cells[i].length; j++) {
+ TableCell cell = cells[i][j];
+
+ if(j != cells[i].length - 1)
+ cell.setBorderRight(cloneBorder(line));
+ else {
+ cell.setBorderLeft(null);
+ cell.setBorderLeft(null);
+ }
+ if(i != cells.length - 1) cell.setBorderBottom(cloneBorder(line));
+ else {
+ cell.setBorderTop(null);
+ cell.setBorderBottom(null);
+ }
+ }
+ }
+ }
+
+ private Line cloneBorder(Line line){
+ Line border = createBorder();
+ border.setLineWidth(line.getLineWidth());
+ border.setLineStyle(line.getLineStyle());
+ border.setLineDashing(line.getLineDashing());
+ border.setLineColor(line.getLineColor());
+ return border;
+ }
+
+ /**
+ * Create a border to format this table
+ *
+ * @return the created border
+ */
+ public Line createBorder(){
+ Line line = new Line(this);
+
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(line.getSpContainer(), EscherOptRecord.RECORD_ID);
+ setEscherProperty(opt, EscherProperties.GEOMETRY__SHAPEPATH, -1);
+ setEscherProperty(opt, EscherProperties.GEOMETRY__FILLOK, -1);
+ setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
+ setEscherProperty(opt, EscherProperties.THREED__LIGHTFACE, 0x80000);
+
+ return line;
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java new file mode 100755 index 0000000000..bb93e06b71 --- /dev/null +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TableCell.java @@ -0,0 +1,155 @@ +
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.hslf.model;
+
+import org.apache.poi.ddf.*;
+import org.apache.poi.hslf.record.EscherTextboxWrapper;
+import org.apache.poi.hslf.record.TextHeaderAtom;
+import org.apache.poi.hslf.usermodel.RichTextRun;
+
+import java.awt.*;
+
+/**
+ * Represents a cell in a ppt table
+ *
+ * @author Yegor Kozlov
+ */
+public class TableCell extends TextBox {
+ protected static final int DEFAULT_WIDTH = 100;
+ protected static final int DEFAULT_HEIGHT = 40;
+
+ private Line borderLeft;
+ private Line borderRight;
+ private Line borderTop;
+ private Line borderBottom;
+
+ /**
+ * Create a TableCell object and initialize it from the supplied Record container.
+ *
+ * @param escherRecord <code>EscherSpContainer</code> container which holds information about this shape
+ * @param parent the parent of the shape
+ */
+ protected TableCell(EscherContainerRecord escherRecord, Shape parent){
+ super(escherRecord, parent);
+ }
+
+ /**
+ * Create a new TableCell. This constructor is used when a new shape is created.
+ *
+ * @param parent the parent of this Shape. For example, if this text box is a cell
+ * in a table then the parent is Table.
+ */
+ public TableCell(Shape parent){
+ super(parent);
+
+ setShapeType(ShapeTypes.Rectangle);
+ _txtrun.setRunType(TextHeaderAtom.HALF_BODY_TYPE);
+ _txtrun.getRichTextRuns()[0].setFlag(false, 0, false);
+ }
+
+ protected EscherContainerRecord createSpContainer(boolean isChild){
+ EscherContainerRecord spContainer = super.createSpContainer(isChild);
+ EscherOptRecord opt = (EscherOptRecord)getEscherChild(spContainer, EscherOptRecord.RECORD_ID);
+ setEscherProperty(opt, EscherProperties.TEXT__TEXTID, 0);
+ setEscherProperty(opt, EscherProperties.TEXT__SIZE_TEXT_TO_FIT_SHAPE, 0x20000);
+ setEscherProperty(opt, EscherProperties.FILL__NOFILLHITTEST, 0x150001);
+ setEscherProperty(opt, EscherProperties.SHADOWSTYLE__SHADOWOBSURED, 0x20000);
+ setEscherProperty(opt, EscherProperties.PROTECTION__LOCKAGAINSTGROUPING, 0x40000);
+
+ return spContainer;
+ }
+
+ protected void anchorBorder(int type, Line line){
+ Rectangle cellAnchor = getAnchor();
+ Rectangle lineAnchor = new Rectangle();
+ switch(type){
+ case Table.BORDER_TOP:
+ lineAnchor.x = cellAnchor.x;
+ lineAnchor.y = cellAnchor.y;
+ lineAnchor.width = cellAnchor.width;
+ lineAnchor.height = 0;
+ break;
+ case Table.BORDER_RIGHT:
+ lineAnchor.x = cellAnchor.x + cellAnchor.width;
+ lineAnchor.y = cellAnchor.y;
+ lineAnchor.width = 0;
+ lineAnchor.height = cellAnchor.height;
+ break;
+ case Table.BORDER_BOTTOM:
+ lineAnchor.x = cellAnchor.x;
+ lineAnchor.y = cellAnchor.y + cellAnchor.height;
+ lineAnchor.width = cellAnchor.width;
+ lineAnchor.height = 0;
+ break;
+ case Table.BORDER_LEFT:
+ lineAnchor.x = cellAnchor.x;
+ lineAnchor.y = cellAnchor.y;
+ lineAnchor.width = 0;
+ lineAnchor.height = cellAnchor.height;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown border type: " + type);
+ }
+ line.setAnchor(lineAnchor);
+ }
+
+ public Line getBorderLeft() {
+ return borderLeft;
+ }
+
+ public void setBorderLeft(Line line) {
+ if(line != null) anchorBorder(Table.BORDER_LEFT, line);
+ this.borderLeft = line;
+ }
+
+ public Line getBorderRight() {
+ return borderRight;
+ }
+
+ public void setBorderRight(Line line) {
+ if(line != null) anchorBorder(Table.BORDER_RIGHT, line);
+ this.borderRight = line;
+ }
+
+ public Line getBorderTop() {
+ return borderTop;
+ }
+
+ public void setBorderTop(Line line) {
+ if(line != null) anchorBorder(Table.BORDER_TOP, line);
+ this.borderTop = line;
+ }
+
+ public Line getBorderBottom() {
+ return borderBottom;
+ }
+
+ public void setBorderBottom(Line line) {
+ if(line != null) anchorBorder(Table.BORDER_BOTTOM, line);
+ this.borderBottom = line;
+ }
+
+ public void setAnchor(Rectangle anchor){
+ super.setAnchor(anchor);
+
+ if(borderTop != null) anchorBorder(Table.BORDER_TOP, borderTop);
+ if(borderRight != null) anchorBorder(Table.BORDER_RIGHT, borderRight);
+ if(borderBottom != null) anchorBorder(Table.BORDER_BOTTOM, borderBottom);
+ if(borderLeft != null) anchorBorder(Table.BORDER_LEFT, borderLeft);
+ }
+}
diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java index 2d5c866f77..1f9a489a78 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextBox.java @@ -196,7 +196,7 @@ public class TextBox extends SimpleShape { } catch (IOException e){ throw new HSLFException(e); } - if(getAnchor().equals(new java.awt.Rectangle())) resizeToFitText(); + if(getAnchor().equals(new java.awt.Rectangle()) && !"".equals(getText())) resizeToFitText(); } /** @@ -264,6 +264,14 @@ public class TextBox extends SimpleShape { EscherOptRecord opt = (EscherOptRecord)getEscherChild(_escherContainer, EscherOptRecord.RECORD_ID); setEscherProperty(opt, EscherProperties.TEXT__ANCHORTEXT, align); } + + public void setHorizontalAlignment(int align){ + _txtrun.getRichTextRuns()[0].setAlignment(align); + } + public int getHorizontalAlignment(){ + return _txtrun.getRichTextRuns()[0].getAlignment(); + } + /** * Returns the distance (in points) between the bottom of the text frame * and the bottom of the inscribed rectangle of the shape that contains the text. @@ -466,7 +474,11 @@ public class TextBox extends SimpleShape { TextRun[] runs = sheet.getTextRuns(); if (ota != null) { int idx = ota.getTextIndex(); - if(idx < runs.length) _txtrun = runs[idx]; + for (int i = 0; i < runs.length; i++) { + if(runs[i].getIndex() == idx){ + _txtrun = runs[i]; + } + } if(_txtrun == null) { logger.log(POILogger.WARN, "text run not found for OutlineTextRefAtom.TextIndex=" + idx); } @@ -478,9 +490,6 @@ public class TextBox extends SimpleShape { break; } } - if(_txtrun == null) { - logger.log(POILogger.WARN, "text run not found for shapeId=" + shapeId); - } } } diff --git a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java index 4999df7581..ca6e02d69b 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java @@ -50,6 +50,7 @@ public class TextRun private SlideShow slideShow; private Sheet sheet; private int shapeId; + private int slwtIndex; //position in the owning SlideListWithText /** * all text run records that follow TextHeaderAtom. * (there can be misc InteractiveInfo, TxInteractiveInfo and other records) @@ -538,6 +539,20 @@ public class TextRun } /** + * @return 0-based index of the text run in the SLWT container + */ + protected int getIndex(){ + return slwtIndex; + } + + /** + * @param id 0-based index of the text run in the SLWT container + */ + protected void setIndex(int id){ + slwtIndex = id; + } + + /** * Returns the array of all hyperlinks in this text run * * @return the array of all hyperlinks in this text run diff --git a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java index 0ee01b9a96..d16bf7bc02 100644 --- a/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java +++ b/src/scratchpad/src/org/apache/poi/hslf/usermodel/RichTextRun.java @@ -198,7 +198,7 @@ public class RichTextRun setFlag(true, index, value); } - private void setFlag(boolean isCharacter, int index, boolean value) { + public void setFlag(boolean isCharacter, int index, boolean value) { TextPropCollection props; String propname; if (isCharacter){ @@ -282,7 +282,7 @@ public class RichTextRun * @param propName The name of the Character TextProp * @param val The value to set for the TextProp */ - private void setParaTextPropVal(String propName, int val) { + public void setParaTextPropVal(String propName, int val) { // Ensure we have the StyleTextProp atom we're going to need if(paragraphStyle == null) { parentRun.ensureStyleAtomPresent(); @@ -297,7 +297,7 @@ public class RichTextRun * @param propName The name of the Paragraph TextProp * @param val The value to set for the TextProp */ - private void setCharTextPropVal(String propName, int val) { + public void setCharTextPropVal(String propName, int val) { // Ensure we have the StyleTextProp atom we're going to need if(characterStyle == null) { parentRun.ensureStyleAtomPresent(); diff --git a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java index ed215f6382..eb915160b3 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/MAPIMessage.java @@ -48,15 +48,24 @@ public class MAPIMessage { /** - * Constructor for reading MSG Files. + * Constructor for reading MSG Files from the file system. * @param filename * @throws IOException */ public MAPIMessage(String filename) throws IOException { - InputStream in = new FileInputStream(new File(filename)); + this(new FileInputStream(new File(filename))); + } + + /** + * Constructor for reading MSG Files from an input stream. + * @param in + * @throws IOException + */ + public MAPIMessage(InputStream in) throws IOException { this.fs = new POIFSFileSystem(in); chunkParser = new POIFSChunkParser(this.fs); } + /** * Gets a string value based on the passed chunk. @@ -102,6 +111,16 @@ public class MAPIMessage { } /** + * Gets the display value of the "FROM" line of the outlook message + * This is not the actual address that was sent from but the formated display of the user name. + * @return + * @throws ChunkNotFoundException + */ + public String getDisplayFrom() throws ChunkNotFoundException { + return getStringFromChunk(Chunks.getInstance().displayFromChunk); + } + + /** * Gets the display value of the "TO" line of the outlook message * This is not the actual list of addresses/values that will be sent to if you click Reply in the email. * @return diff --git a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java index 309efeac9d..6a3936d964 100644 --- a/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java +++ b/src/scratchpad/src/org/apache/poi/hsmf/datatypes/Chunks.java @@ -29,6 +29,7 @@ public class Chunks { public StringChunk textBodyChunk = new StringChunk(0x1000); //BODY Chunk, for plain/text messages public StringChunk subjectChunk = new StringChunk(0x0037); //Subject link chunk, in plain/text public StringChunk displayToChunk = new StringChunk(0x0E04); //Value that is in the TO field (not actually the addresses as they are stored in recip directory nodes + public StringChunk displayFromChunk = new StringChunk(0x0C1A); //Value that is in the FROM field public StringChunk displayCCChunk = new StringChunk(0x0E03); //value that shows in the CC field public StringChunk displayBCCChunk = new StringChunk(0x0E02); //Value that shows in the BCC field public StringChunk conversationTopic = new StringChunk(0x0070); //Sort of like the subject line, but without the RE: and FWD: parts. diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java index 34dcc7cdae..6861a02524 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Date.java @@ -70,7 +70,7 @@ public class Date extends NumericFunction { c.set(year, month, day, 0, 0, 0); c.set(Calendar.MILLISECOND, 0); - return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime())); + return new NumberEval(HSSFDateUtil.getExcelDate(c.getTime(), false)); // XXX fix 1900/1904 problem } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java index 283633442e..0ae5694767 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Day.java @@ -46,7 +46,7 @@ srcCellRow, srcCellCol); if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem java.util.Calendar c = java.util.Calendar.getInstance(); c.setTime(d); retval = new NumberEval(c.get(java.util.Calendar.DAY_OF_MONTH)); diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java index 30593142e8..d6c4399ae3 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Mid.java @@ -20,6 +20,80 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Mid extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the MID function: + * Returns a specific number of characters from a text string, + * starting at the position you specify, based on the number + * of characters you specify. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Mid extends TextFunction { + /** + * Returns a specific number of characters from a text string, + * starting at the position you specify, based on the number + * of characters you specify. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String str = null; + int startNum = 0; + int numChars = 0; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 3: + // first operand is text string containing characters to extract + // second operand is position of first character to extract + // third operand is the number of characters to return + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof NumericValueEval + && thirdveval instanceof NumericValueEval) { + + StringValueEval strEval = (StringValueEval) firstveval; + str = strEval.getStringValue(); + + NumericValueEval startNumEval = (NumericValueEval) secondveval; + // NOTE: it is safe to cast to int here + // because in Excel =MID("test", 1, 1.7) returns t + // so 1.7 must be truncated to 1 + // and =MID("test", 1.9, 2) returns te + // so 1.9 must be truncated to 1 + startNum = (int) startNumEval.getNumberValue(); + + NumericValueEval numCharsEval = (NumericValueEval) thirdveval; + numChars = (int) numCharsEval.getNumberValue(); + + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (startNum < 1 || numChars < 0) { + retval = ErrorEval.VALUE_INVALID; + } else if (startNum > str.length() || numChars == 0) { + retval = BlankEval.INSTANCE; + } else if (startNum + numChars > str.length()) { + retval = new StringEval(str.substring(startNum - 1)); + } else { + retval = new StringEval(str.substring(startNum - 1, numChars)); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java index 065c565d14..d5178b22df 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Month.java @@ -50,7 +50,7 @@ public class Month extends NumericFunction { if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem retval = new NumberEval(d.getMonth()+1); } else { retval = ErrorEval.NUM_ERROR; diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java index 3ba7a2b2ce..95413f0823 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Replace.java @@ -20,6 +20,93 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Replace extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the REPLACE function: + * Replaces part of a text string based on the number of characters + * you specify, with another text string. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Replace extends TextFunction { + + /** + * Replaces part of a text string based on the number of characters + * you specify, with another text string. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String oldStr = null; + String newStr = null; + int startNum = 0; + int numChars = 0; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 4: + // first operand is text string containing characters to replace + // second operand is position of first character to replace + // third operand is the number of characters in the old string + // you want to replace with new string + // fourth operand is the new string + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof NumericValueEval + && thirdveval instanceof NumericValueEval + && fourthveval instanceof StringValueEval) { + + StringValueEval oldStrEval = (StringValueEval) firstveval; + oldStr = oldStrEval.getStringValue(); + + NumericValueEval startNumEval = (NumericValueEval) secondveval; + // NOTE: it is safe to cast to int here + // because in Excel =REPLACE("task", 2.7, 3, "est") + // returns test + // so 2.7 must be truncated to 2 + // and =REPLACE("task", 1, 1.9, "") returns ask + // so 1.9 must be truncated to 1 + startNum = (int) startNumEval.getNumberValue(); + + NumericValueEval numCharsEval = (NumericValueEval) thirdveval; + numChars = (int) numCharsEval.getNumberValue(); + + StringValueEval newStrEval = (StringValueEval) fourthveval; + newStr = newStrEval.getStringValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (startNum < 1 || numChars < 0) { + retval = ErrorEval.VALUE_INVALID; + } else { + StringBuffer strBuff = new StringBuffer(oldStr); + // remove any characters that should be replaced + if (startNum <= oldStr.length() && numChars != 0) { + strBuff.delete(startNum - 1, startNum - 1 + numChars); + } + // now insert (or append) newStr + if (startNum > strBuff.length()) { + strBuff.append(newStr); + } else { + strBuff.insert(startNum - 1, newStr); + } + retval = new StringEval(strBuff.toString()); + } + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java index 8a975c569e..9d2e9ce361 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Substitute.java @@ -20,6 +20,98 @@ */ package org.apache.poi.hssf.record.formula.functions; -public class Substitute extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumericValueEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; +/** + * An implementation of the SUBSTITUTE function: + * Substitutes text in a text string with new text, some number of times. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Substitute extends TextFunction { + private static final int REPLACE_ALL = -1; + + /** + *Substitutes text in a text string with new text, some number of times. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = null; + String oldStr = null; + String searchStr = null; + String newStr = null; + int numToReplace = REPLACE_ALL; + + switch (operands.length) { + default: + retval = ErrorEval.VALUE_INVALID; + case 4: + ValueEval fourthveval = singleOperandEvaluate(operands[3], srcCellRow, srcCellCol); + if (fourthveval instanceof NumericValueEval) { + NumericValueEval numToReplaceEval = (NumericValueEval) fourthveval; + // NOTE: it is safe to cast to int here + // because in Excel =SUBSTITUTE("teststr","t","T",1.9) + // returns Teststr + // so 1.9 must be truncated to 1 + numToReplace = (int) numToReplaceEval.getNumberValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + case 3: + // first operand is text string containing characters to replace + // second operand is text to find + // third operand is replacement text + ValueEval firstveval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + ValueEval secondveval = singleOperandEvaluate(operands[1], srcCellRow, srcCellCol); + ValueEval thirdveval = singleOperandEvaluate(operands[2], srcCellRow, srcCellCol); + if (firstveval instanceof StringValueEval + && secondveval instanceof StringValueEval + && thirdveval instanceof StringValueEval) { + + StringValueEval oldStrEval = (StringValueEval) firstveval; + oldStr = oldStrEval.getStringValue(); + + StringValueEval searchStrEval = (StringValueEval) secondveval; + searchStr = searchStrEval.getStringValue(); + + StringValueEval newStrEval = (StringValueEval) thirdveval; + newStr = newStrEval.getStringValue(); + } else { + retval = ErrorEval.VALUE_INVALID; + } + } + + if (retval == null) { + if (numToReplace != REPLACE_ALL && numToReplace < 1) { + retval = ErrorEval.VALUE_INVALID; + } else if (searchStr.length() == 0) { + retval = new StringEval(oldStr); + } else { + StringBuffer strBuff = new StringBuffer(); + int startIndex = 0; + int nextMatch = -1; + for (int leftToReplace = numToReplace; + (leftToReplace > 0 || numToReplace == REPLACE_ALL) + && (nextMatch = oldStr.indexOf(searchStr, startIndex)) != -1; + leftToReplace--) { + // store everything from end of last match to start of this match + strBuff.append(oldStr.substring(startIndex, nextMatch)); + strBuff.append(newStr); + startIndex = nextMatch + searchStr.length(); + } + // store everything from end of last match to end of string + if (startIndex < oldStr.length()) { + strBuff.append(oldStr.substring(startIndex)); + } + retval = new StringEval(strBuff.toString()); + } + } + return retval; + } + } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java index 69b3ce6f55..5e9d91c7cc 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Trim.java @@ -14,12 +14,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -/* - * Created on May 15, 2005 - * - */ package org.apache.poi.hssf.record.formula.functions; -public class Trim extends NotImplementedFunction { +import org.apache.poi.hssf.record.formula.eval.BlankEval; +import org.apache.poi.hssf.record.formula.eval.ErrorEval; +import org.apache.poi.hssf.record.formula.eval.Eval; +import org.apache.poi.hssf.record.formula.eval.NumberEval; +import org.apache.poi.hssf.record.formula.eval.StringEval; +import org.apache.poi.hssf.record.formula.eval.StringValueEval; +import org.apache.poi.hssf.record.formula.eval.ValueEval; + +/** + * An implementation of the TRIM function: + * Removes leading and trailing spaces from value if evaluated operand + * value is string. + * @author Manda Wilson < wilson at c bio dot msk cc dot org > + */ +public class Trim extends TextFunction { + /** + * Removes leading and trailing spaces from value if evaluated + * operand value is string. + * Returns StringEval only if evaluated operand is of type string + * (and is not blank or null) or number. If evaluated operand is + * of type string and is blank or null, or if evaluated operand is + * of type blank, returns BlankEval. Otherwise returns ErrorEval. + * + * @see org.apache.poi.hssf.record.formula.eval.Eval + */ + public Eval evaluate(Eval[] operands, int srcCellRow, short srcCellCol) { + Eval retval = ErrorEval.VALUE_INVALID; + String str = null; + + switch (operands.length) { + default: + break; + case 1: + ValueEval veval = singleOperandEvaluate(operands[0], srcCellRow, srcCellCol); + if (veval instanceof StringValueEval) { + StringValueEval sve = (StringValueEval) veval; + str = sve.getStringValue(); + if (str == null || str.trim().equals("")) { + return BlankEval.INSTANCE; + } + } + else if (veval instanceof NumberEval) { + NumberEval neval = (NumberEval) veval; + str = neval.getStringValue(); + } + else if (veval instanceof BlankEval) { + return BlankEval.INSTANCE; + } + } + + if (str != null) { + retval = new StringEval(str.trim()); + } + return retval; + } } diff --git a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java index 76ea617cc6..b461a09668 100644 --- a/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java +++ b/src/scratchpad/src/org/apache/poi/hssf/record/formula/functions/Year.java @@ -51,7 +51,7 @@ public class Year extends NumericFunction { if (ve instanceof NumericValueEval) { NumericValueEval ne = (NumericValueEval) ve; if (HSSFDateUtil.isValidExcelDate(ne.getNumberValue())) { - java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue()); + java.util.Date d = HSSFDateUtil.getJavaDate(ne.getNumberValue(), false); // XXX fix 1900/1904 problem retval = new NumberEval(d.getYear()+1900); } else { retval = ErrorEval.NUM_ERROR; diff --git a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java index cec20c91e6..4196566d9a 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/model/ListTables.java @@ -19,6 +19,8 @@ package org.apache.poi.hwpf.model; import org.apache.poi.util.LittleEndian; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; import org.apache.poi.hwpf.model.io.*; @@ -37,6 +39,7 @@ public class ListTables { private static final int LIST_DATA_SIZE = 28; private static final int LIST_FORMAT_OVERRIDE_SIZE = 16; + private static POILogger log = POILogFactory.getLogger(ListTables.class); HashMap _listMap = new HashMap(); ArrayList _overrideList = new ArrayList(); @@ -189,8 +192,13 @@ public class ListTables public ListLevel getLevel(int listID, int level) { ListData lst = (ListData)_listMap.get(new Integer(listID)); - ListLevel lvl = lst.getLevels()[level]; - return lvl; + if(level < lst.numLevels()) { + ListLevel lvl = lst.getLevels()[level]; + return lvl; + } else { + log.log(POILogger.WARN, "Requested level " + level + " which was greater than the maximum defined (" + lst.numLevels() + ")"); + return null; + } } public ListData getListData(int listID) diff --git a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java index 87547565f2..f8fc91f123 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/sprm/TableSprmUncompressor.java @@ -148,8 +148,10 @@ public class TableSprmUncompressor for (int x = 0; x < itcMac; x++) { - if(hasTCs) rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl, - offset + (1 + ( (itcMac + 1) * 2) + (x * 20))); + // Sometimes, the grpprl does not contain data at every offset. I have no idea why this happens. + if(hasTCs && offset + (1 + ( (itcMac + 1) * 2) + (x * 20)) < grpprl.length) + rgtc[x] = TableCellDescriptor.convertBytesToTC(grpprl, + offset + (1 + ( (itcMac + 1) * 2) + (x * 20))); else rgtc[x] = new TableCellDescriptor(); } diff --git a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java index 1b0ba626c2..9bafce7927 100644 --- a/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java +++ b/src/scratchpad/src/org/apache/poi/hwpf/usermodel/ListEntry.java @@ -23,21 +23,28 @@ import org.apache.poi.hwpf.model.ListFormatOverrideLevel; import org.apache.poi.hwpf.model.ListLevel; import org.apache.poi.hwpf.model.ListTables; import org.apache.poi.hwpf.model.PAPX; - -import org.apache.poi.hwpf.sprm.SprmBuffer; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; public class ListEntry extends Paragraph { - ListLevel _level; - ListFormatOverrideLevel _overrideLevel; + private static POILogger log = POILogFactory.getLogger(ListEntry.class); + + ListLevel _level; + ListFormatOverrideLevel _overrideLevel; ListEntry(PAPX papx, Range parent, ListTables tables) { super(papx, parent); - ListFormatOverride override = tables.getOverride(_props.getIlfo()); - _overrideLevel = override.getOverrideLevel(_props.getIlvl()); - _level = tables.getLevel(override.getLsid(), _props.getIlvl()); + + if(tables != null) { + ListFormatOverride override = tables.getOverride(_props.getIlfo()); + _overrideLevel = override.getOverrideLevel(_props.getIlvl()); + _level = tables.getLevel(override.getLsid(), _props.getIlvl()); + } else { + log.log(POILogger.WARN, "No ListTables found for ListEntry - document probably partly corrupt, and you may experience problems"); + } } public int type() diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt Binary files differnew file mode 100755 index 0000000000..ddea91fe89 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/data/43781.ppt diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx Binary files differnew file mode 100644 index 0000000000..fbd540c1e0 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hslf/data/sample.pptx diff --git a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java index 933aa176b7..996a733ac9 100644 --- a/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java +++ b/src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestBugs.java @@ -25,6 +25,7 @@ import org.apache.poi.hslf.model.Shape; import java.io.*;
import java.util.HashSet;
import java.util.HashMap;
+import java.util.ArrayList;
import java.awt.*;
/**
@@ -298,4 +299,35 @@ public class TestBugs extends TestCase { }
+ /**
+ * Bug 38256: RuntimeException: Couldn't instantiate the class for type with id 0.
+ * ( also fixed followup: getTextRuns() returns no text )
+ */
+ public void test43781 () throws Exception {
+ FileInputStream is = new FileInputStream(new File(cwd, "43781.ppt"));
+ SlideShow ppt = new SlideShow(is);
+ is.close();
+
+ assertTrue("No Exceptions while reading file", true);
+
+ Slide slide = ppt.getSlides()[0];
+ TextRun[] tr1 = slide.getTextRuns();
+
+ ArrayList lst = new ArrayList();
+ Shape[] shape = slide.getShapes();
+ for (int i = 0; i < shape.length; i++) {
+ if( shape[i] instanceof TextBox){
+ TextRun textRun = ((TextBox)shape[i]).getTextRun();
+ if(textRun != null) lst.add(textRun);
+ }
+
+ }
+ TextRun[] tr2 = new TextRun[lst.size()];
+ lst.toArray(tr2);
+
+ assertEquals(tr1.length, tr2.length);
+ for (int i = 0; i < tr1.length; i++) {
+ assertEquals(tr1[i].getText(), tr2[i].getText());
+ }
+ }
}
diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java index 05735870b4..314cc506c4 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestBlankFileRead.java @@ -84,6 +84,21 @@ public class TestBlankFileRead extends TestCase { } /** + * Test to see if we can read the FROM Chunk. + * @throws ChunkNotFoundException + * + */ + public void testReadDisplayFrom() throws ChunkNotFoundException { + try { + mapiMessage.getDisplayFrom(); + } catch(ChunkNotFoundException exp) { + return; + } + + TestCase.fail("Should have thrown a ChunkNotFoundException but didn't"); + } + + /** * Test to see if we can read the CC Chunk. * @throws ChunkNotFoundException * diff --git a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java index 0ede68965a..925685218d 100644 --- a/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java +++ b/src/scratchpad/testcases/org/apache/poi/hsmf/model/TestSimpleFileRead.java @@ -67,6 +67,18 @@ private MAPIMessage mapiMessage; } /** + * Test to see if we can read the From Chunk. + * @throws ChunkNotFoundException + * + */ + public void testReadDisplayFrom() throws ChunkNotFoundException { + String obtained = mapiMessage.getDisplayFrom(); + String expected = "Travis Ferguson"; + + TestCase.assertEquals(obtained, expected); + } + + /** * Test to see if we can read the CC Chunk. * @throws ChunkNotFoundException * diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls Binary files differindex b2388f1d03..cf4b6fa501 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls +++ b/src/scratchpad/testcases/org/apache/poi/hssf/data/FormulaEvalTestData.xls diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java index d1ab0c7076..ac3ca2eb29 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/eval/TestEverything.java @@ -23,27 +23,37 @@ package org.apache.poi.hssf.record.formula.eval; import junit.framework.TestSuite; /** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * This is a test of all the Eval functions we have implemented. + * Add newly implemented Eval functions in here to have them + * tested. + * For newly implemented functions, + * @see org.apache.poi.hssf.record.formula.functions.TestEverything * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > */ public class TestEverything extends TestSuite { public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Tests for OperationEval concrete implementation classes."); - suite.addTest(new GenericFormulaTestCase("D23")); - suite.addTest(new GenericFormulaTestCase("D27")); - suite.addTest(new GenericFormulaTestCase("D31")); - suite.addTest(new GenericFormulaTestCase("D35")); - suite.addTest(new GenericFormulaTestCase("D39")); - suite.addTest(new GenericFormulaTestCase("D43")); - suite.addTest(new GenericFormulaTestCase("D47")); - suite.addTest(new GenericFormulaTestCase("D51")); - suite.addTest(new GenericFormulaTestCase("D55")); - suite.addTest(new GenericFormulaTestCase("D59")); - suite.addTest(new GenericFormulaTestCase("D63")); - suite.addTest(new GenericFormulaTestCase("D67")); - suite.addTest(new GenericFormulaTestCase("D71")); - suite.addTest(new GenericFormulaTestCase("D75")); + suite.addTest(new GenericFormulaTestCase("D23")); // Add + suite.addTest(new GenericFormulaTestCase("D27")); // ConcatEval + suite.addTest(new GenericFormulaTestCase("D31")); // DivideEval + suite.addTest(new GenericFormulaTestCase("D35")); // EqualEval + suite.addTest(new GenericFormulaTestCase("D39")); // GreaterEqualEval + suite.addTest(new GenericFormulaTestCase("D43")); // GreaterThanEval + suite.addTest(new GenericFormulaTestCase("D47")); // LessEqualEval + suite.addTest(new GenericFormulaTestCase("D51")); // LessThanEval + suite.addTest(new GenericFormulaTestCase("D55")); // MultiplyEval + suite.addTest(new GenericFormulaTestCase("D59")); // NotEqualEval + suite.addTest(new GenericFormulaTestCase("D63")); // PowerEval + suite.addTest(new GenericFormulaTestCase("D67")); // SubtractEval + suite.addTest(new GenericFormulaTestCase("D71")); // UnaryMinusEval + suite.addTest(new GenericFormulaTestCase("D75")); // UnaryPlusEval + + // Add newly implemented Eval functions here + // (Formula functions go in + // @see org.apache.poi.hssf.record.formula.functions.TestEverything ) + return suite; } } diff --git a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java index ad93996339..8337810216 100644 --- a/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java +++ b/src/scratchpad/testcases/org/apache/poi/hssf/record/formula/functions/TestEverything.java @@ -25,11 +25,16 @@ import org.apache.poi.hssf.record.formula.eval.GenericFormulaTestCase; import junit.framework.TestSuite; /** - * @author Amol S. Deshmukh < amolweb at ya hoo dot com > + * This is a test of all the normal formula functions we have implemented. + * It should pick up newly implemented functions which are correctly added + * to the test formula excel file, but tweak the rows below if you + * add any past the end of what's currently checked. + * For newly implemented eval functions, + * @see org.apache.poi.hssf.record.formula.eval.TestEverything * + * @author Amol S. Deshmukh < amolweb at ya hoo dot com > */ public class TestEverything extends TestSuite { - public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Tests for individual function classes"); String s; diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc Binary files differnew file mode 100644 index 0000000000..bfd5906caa --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/AIOOB-Tap.doc diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx Binary files differnew file mode 100644 index 0000000000..29dacb652e --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/IllustrativeCases.docx diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc Binary files differnew file mode 100644 index 0000000000..939f5a4a9e --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/ListEntryNoListTable.doc diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx Binary files differnew file mode 100644 index 0000000000..8dd04bcdb8 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/data/sample.docx diff --git a/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java new file mode 100644 index 0000000000..8e7f47ed96 --- /dev/null +++ b/src/scratchpad/testcases/org/apache/poi/hwpf/usermodel/TestProblems.java @@ -0,0 +1,77 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one or more +* contributor license agreements. See the NOTICE file distributed with +* this work for additional information regarding copyright ownership. +* The ASF licenses this file to You under the Apache License, Version 2.0 +* (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package org.apache.poi.hwpf.usermodel; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.hwpf.HWPFDocument; +import org.apache.poi.hwpf.model.StyleSheet; +import org.apache.poi.hwpf.model.TextPiece; +import org.apache.poi.hwpf.usermodel.Paragraph; +import org.apache.poi.hwpf.usermodel.Range; +import org.apache.poi.util.LittleEndian; + +import junit.framework.TestCase; + +/** + * Test various problem documents + * + * @author Nick Burch (nick at torchbox dot com) + */ +public class TestProblems extends TestCase { + private String dirname = System.getProperty("HWPF.testdata.path"); + + protected void setUp() throws Exception { + } + + /** + * ListEntry passed no ListTable + */ + public void testListEntryNoListTable() throws Exception { + HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/ListEntryNoListTable.doc")); + + Range r = doc.getRange(); + StyleSheet styleSheet = doc.getStyleSheet(); + for (int x = 0; x < r.numSections(); x++) { + Section s = r.getSection(x); + for (int y = 0; y < s.numParagraphs(); y++) { + Paragraph paragraph = s.getParagraph(y); + //System.out.println(paragraph.getCharacterRun(0).text()); + } + } + } + + /** + * AIOOB for TableSprmUncompressor.unCompressTAPOperation + */ + public void testSprmAIOOB() throws Exception { + HWPFDocument doc = new HWPFDocument(new FileInputStream(dirname + "/AIOOB-Tap.doc")); + + Range r = doc.getRange(); + StyleSheet styleSheet = doc.getStyleSheet(); + for (int x = 0; x < r.numSections(); x++) { + Section s = r.getSection(x); + for (int y = 0; y < s.numParagraphs(); y++) { + Paragraph paragraph = s.getParagraph(y); + //System.out.println(paragraph.getCharacterRun(0).text()); + } + } + } +} |