001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: /*
019: * HSSFRow.java
020: *
021: * Created on September 30, 2001, 3:44 PM
022: */
023: package org.apache.poi.hssf.usermodel;
024:
025: import org.apache.poi.hssf.model.Sheet;
026: import org.apache.poi.hssf.model.Workbook;
027: import org.apache.poi.hssf.record.CellValueRecordInterface;
028: import org.apache.poi.hssf.record.RowRecord;
029:
030: import java.util.HashMap;
031: import java.util.Iterator;
032: import java.util.NoSuchElementException;
033:
034: /**
035: * High level representation of a row of a spreadsheet.
036: *
037: * Only rows that have cells should be added to a Sheet.
038: * @version 1.0-pre
039: * @author Andrew C. Oliver (acoliver at apache dot org)
040: * @author Glen Stampoultzis (glens at apache.org)
041: */
042:
043: public class HSSFRow implements Comparable {
044:
045: // used for collections
046: public final static int INITIAL_CAPACITY = 5;
047: //private short rowNum;
048: private int rowNum;
049: private HSSFCell[] cells = new HSSFCell[INITIAL_CAPACITY];
050: // private short firstcell = -1;
051: // private short lastcell = -1;
052:
053: /**
054: * reference to low level representation
055: */
056:
057: private RowRecord row;
058:
059: /**
060: * reference to containing low level Workbook
061: */
062:
063: private Workbook book;
064:
065: /**
066: * reference to containing Sheet
067: */
068:
069: private Sheet sheet;
070:
071: protected HSSFRow() {
072: }
073:
074: /**
075: * Creates new HSSFRow from scratch. Only HSSFSheet should do this.
076: *
077: * @param book low-level Workbook object containing the sheet that contains this row
078: * @param sheet low-level Sheet object that contains this Row
079: * @param rowNum the row number of this row (0 based)
080: * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
081: */
082:
083: //protected HSSFRow(Workbook book, Sheet sheet, short rowNum)
084: protected HSSFRow(Workbook book, Sheet sheet, int rowNum) {
085: this .rowNum = rowNum;
086: this .book = book;
087: this .sheet = sheet;
088: row = new RowRecord();
089: row.setOptionFlags((short) 0x100); // seems necessary for outlining to work.
090: row.setHeight((short) 0xff);
091: row.setLastCol((short) -1);
092: row.setFirstCol((short) -1);
093:
094: setRowNum(rowNum);
095: }
096:
097: /**
098: * Creates an HSSFRow from a low level RowRecord object. Only HSSFSheet should do
099: * this. HSSFSheet uses this when an existing file is read in.
100: *
101: * @param book low-level Workbook object containing the sheet that contains this row
102: * @param sheet low-level Sheet object that contains this Row
103: * @param record the low level api object this row should represent
104: * @see org.apache.poi.hssf.usermodel.HSSFSheet#createRow(int)
105: */
106:
107: protected HSSFRow(Workbook book, Sheet sheet, RowRecord record) {
108: this .book = book;
109: this .sheet = sheet;
110: row = record;
111:
112: setRowNum(record.getRowNumber());
113: }
114:
115: /**
116: * Use this to create new cells within the row and return it.
117: * <p>
118: * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
119: * either through calling <code>setCellValue</code> or <code>setCellType</code>.
120: *
121: * @param column - the column number this cell represents
122: *
123: * @return HSSFCell a high level representation of the created cell.
124: */
125:
126: public HSSFCell createCell(short column) {
127: return this .createCell(column, HSSFCell.CELL_TYPE_BLANK);
128: }
129:
130: /**
131: * Use this to create new cells within the row and return it.
132: * <p>
133: * The cell that is returned is a CELL_TYPE_BLANK. The type can be changed
134: * either through calling setCellValue or setCellType.
135: *
136: * @param column - the column number this cell represents
137: *
138: * @return HSSFCell a high level representation of the created cell.
139: */
140:
141: public HSSFCell createCell(short column, int type) {
142: HSSFCell cell = new HSSFCell(book, sheet, getRowNum(), column,
143: type);
144:
145: addCell(cell);
146: sheet.addValueRecord(getRowNum(), cell.getCellValueRecord());
147: return cell;
148: }
149:
150: /**
151: * remove the HSSFCell from this row.
152: * @param cell to remove
153: */
154: public void removeCell(HSSFCell cell) {
155: CellValueRecordInterface cval = cell.getCellValueRecord();
156:
157: sheet.removeValueRecord(getRowNum(), cval);
158: short column = cell.getCellNum();
159: if (cell != null && column < cells.length) {
160: cells[column] = null;
161: }
162:
163: if (cell.getCellNum() == row.getLastCol()) {
164: row.setLastCol(findLastCell(row.getLastCol()));
165: }
166: if (cell.getCellNum() == row.getFirstCol()) {
167: row.setFirstCol(findFirstCell(row.getFirstCol()));
168: }
169: }
170:
171: /**
172: * create a high level HSSFCell object from an existing low level record. Should
173: * only be called from HSSFSheet or HSSFRow itself.
174: * @param cell low level cell to create the high level representation from
175: * @return HSSFCell representing the low level record passed in
176: */
177:
178: protected HSSFCell createCellFromRecord(
179: CellValueRecordInterface cell) {
180: HSSFCell hcell = new HSSFCell(book, sheet, getRowNum(), cell);
181:
182: addCell(hcell);
183:
184: // sheet.addValueRecord(getRowNum(),cell.getCellValueRecord());
185: return hcell;
186: }
187:
188: /**
189: * set the row number of this row.
190: * @param rowNum the row number (0-based)
191: * @throws IndexOutOfBoundsException if the row number is not within the range 0-65535.
192: */
193:
194: //public void setRowNum(short rowNum)
195: public void setRowNum(int rowNum) {
196: if ((rowNum < 0) || (rowNum > RowRecord.MAX_ROW_NUMBER))
197: throw new IndexOutOfBoundsException(
198: "Row number must be between 0 and "
199: + RowRecord.MAX_ROW_NUMBER + ", was <"
200: + rowNum + ">");
201: this .rowNum = rowNum;
202: if (row != null) {
203: row.setRowNumber(rowNum); // used only for KEY comparison (HSSFRow)
204: }
205: }
206:
207: /**
208: * get row number this row represents
209: * @return the row number (0 based)
210: */
211:
212: //public short getRowNum()
213: public int getRowNum() {
214: return rowNum;
215: }
216:
217: /**
218: * used internally to add a cell.
219: */
220:
221: private void addCell(HSSFCell cell) {
222: short column = cell.getCellNum();
223: if (row.getFirstCol() == -1) {
224: row.setFirstCol(column);
225: }
226: if (row.getLastCol() == -1) {
227: row.setLastCol(column);
228: }
229:
230: if (column >= cells.length) {
231: HSSFCell[] oldCells = cells;
232: int newSize = oldCells.length * 2;
233: if (newSize < column + 1)
234: newSize = column + 1;
235: cells = new HSSFCell[newSize];
236: System.arraycopy(oldCells, 0, cells, 0, oldCells.length);
237: }
238: cells[column] = cell;
239:
240: if (column < row.getFirstCol()) {
241: row.setFirstCol(column);
242: }
243: if (column > row.getLastCol()) {
244: row.setLastCol(column);
245: }
246: }
247:
248: /**
249: * get the hssfcell representing a given column (logical cell) 0-based. If you
250: * ask for a cell that is not defined....you get a null.
251: *
252: * @param cellnum 0 based column number
253: * @return HSSFCell representing that column or null if undefined.
254: */
255:
256: public HSSFCell getCell(short cellnum) {
257: if (cellnum < 0 || cellnum >= cells.length)
258: return null;
259: return cells[cellnum];
260: }
261:
262: /**
263: * get the number of the first cell contained in this row.
264: * @return short representing the first logical cell in the row, or -1 if the row does not contain any cells.
265: */
266:
267: public short getFirstCellNum() {
268: if (getPhysicalNumberOfCells() == 0)
269: return -1;
270: else
271: return row.getFirstCol();
272: }
273:
274: /**
275: * gets the number of the last cell contained in this row <b>PLUS ONE</b>.
276: * @return short representing the last logical cell in the row <b>PLUS ONE</b>, or -1 if the row does not contain any cells.
277: */
278:
279: public short getLastCellNum() {
280: if (getPhysicalNumberOfCells() == 0)
281: return -1;
282: else
283: return row.getLastCol();
284: }
285:
286: /**
287: * gets the number of defined cells (NOT number of cells in the actual row!).
288: * That is to say if only columns 0,4,5 have values then there would be 3.
289: * @return int representing the number of defined cells in the row.
290: */
291:
292: public int getPhysicalNumberOfCells() {
293: int count = 0;
294: for (int i = 0; i < cells.length; i++) {
295: if (cells[i] != null)
296: count++;
297: }
298: return count;
299: }
300:
301: /**
302: * set the row's height or set to ff (-1) for undefined/default-height. Set the height in "twips" or
303: * 1/20th of a point.
304: * @param height rowheight or 0xff for undefined (use sheet default)
305: */
306:
307: public void setHeight(short height) {
308:
309: // row.setOptionFlags(
310: row.setBadFontHeight(true);
311: row.setHeight(height);
312: }
313:
314: /**
315: * set whether or not to display this row with 0 height
316: * @param zHeight height is zero or not.
317: */
318: public void setZeroHeight(boolean zHeight) {
319: row.setZeroHeight(zHeight);
320: }
321:
322: /**
323: * get whether or not to display this row with 0 height
324: * @return - zHeight height is zero or not.
325: */
326: public boolean getZeroHeight() {
327: return row.getZeroHeight();
328: }
329:
330: /**
331: * set the row's height in points.
332: * @param height row height in points
333: */
334:
335: public void setHeightInPoints(float height) {
336:
337: // row.setOptionFlags(
338: row.setBadFontHeight(true);
339: row.setHeight((short) (height * 20));
340: }
341:
342: /**
343: * get the row's height or ff (-1) for undefined/default-height in twips (1/20th of a point)
344: * @return rowheight or 0xff for undefined (use sheet default)
345: */
346:
347: public short getHeight() {
348: return row.getHeight();
349: }
350:
351: /**
352: * get the row's height or ff (-1) for undefined/default-height in points (20*getHeight())
353: * @return rowheight or 0xff for undefined (use sheet default)
354: */
355:
356: public float getHeightInPoints() {
357: return (row.getHeight() / 20);
358: }
359:
360: /**
361: * get the lowlevel RowRecord represented by this object - should only be called
362: * by other parts of the high level API
363: *
364: * @return RowRecord this row represents
365: */
366:
367: protected RowRecord getRowRecord() {
368: return row;
369: }
370:
371: /**
372: * used internally to refresh the "last cell" when the last cell is removed.
373: */
374:
375: private short findLastCell(short lastcell) {
376: short cellnum = (short) (lastcell - 1);
377: HSSFCell r = getCell(cellnum);
378:
379: while (r == null && cellnum >= 0) {
380: r = getCell(--cellnum);
381: }
382: return cellnum;
383: }
384:
385: /**
386: * used internally to refresh the "first cell" when the first cell is removed.
387: */
388:
389: private short findFirstCell(short firstcell) {
390: short cellnum = (short) (firstcell + 1);
391: HSSFCell r = getCell(cellnum);
392:
393: while (r == null && cellnum <= getLastCellNum()) {
394: r = getCell(++cellnum);
395: }
396: if (cellnum > getLastCellNum())
397: return -1;
398: return cellnum;
399: }
400:
401: /**
402: * @return cell iterator of the physically defined cells. Note element 4 may
403: * actually be row cell depending on how many are defined!
404: */
405:
406: public Iterator cellIterator() {
407: return new CellIterator();
408: }
409:
410: private class CellIterator implements Iterator {
411: int this Id = -1;
412: int nextId = -1;
413:
414: public CellIterator() {
415: findNext();
416: }
417:
418: public boolean hasNext() {
419: return nextId < cells.length;
420: }
421:
422: public Object next() {
423: if (!hasNext())
424: throw new NoSuchElementException("At last element");
425: HSSFCell cell = cells[nextId];
426: this Id = nextId;
427: findNext();
428: return cell;
429: }
430:
431: public void remove() {
432: if (this Id == -1)
433: throw new IllegalStateException(
434: "remove() called before next()");
435: cells[this Id] = null;
436: }
437:
438: private void findNext() {
439: int i = nextId + 1;
440: for (; i < cells.length; i++) {
441: if (cells[i] != null)
442: break;
443: }
444: nextId = i;
445: }
446:
447: }
448:
449: public int compareTo(Object obj) {
450: HSSFRow loc = (HSSFRow) obj;
451:
452: if (this .getRowNum() == loc.getRowNum()) {
453: return 0;
454: }
455: if (this .getRowNum() < loc.getRowNum()) {
456: return -1;
457: }
458: if (this .getRowNum() > loc.getRowNum()) {
459: return 1;
460: }
461: return -1;
462: }
463:
464: public boolean equals(Object obj) {
465: if (!(obj instanceof HSSFRow)) {
466: return false;
467: }
468: HSSFRow loc = (HSSFRow) obj;
469:
470: if (this .getRowNum() == loc.getRowNum()) {
471: return true;
472: }
473: return false;
474: }
475: }
|