xref: /trunk/main/xmerge/java/pexcel/src/main/java/org/openoffice/xmerge/converter/xml/sxc/pexcel/records/Workbook.java (revision 3309286857f19787ae62bd793a98b5af4edd2ad3)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml.sxc.pexcel.records;
25 
26 import java.io.OutputStream;
27 import java.io.InputStream;
28 import java.io.IOException;
29 import java.util.Vector;
30 import java.util.Enumeration;
31 
32 import org.openoffice.xmerge.converter.xml.OfficeConstants;
33 import org.openoffice.xmerge.converter.xml.sxc.Format;
34 import org.openoffice.xmerge.converter.xml.sxc.NameDefinition;
35 import org.openoffice.xmerge.converter.xml.sxc.BookSettings;
36 import org.openoffice.xmerge.converter.xml.sxc.SheetSettings;
37 import org.openoffice.xmerge.util.Debug;
38 import org.openoffice.xmerge.converter.xml.sxc.pexcel.PocketExcelConstants;
39 import org.openoffice.xmerge.converter.xml.sxc.ColumnRowInfo;
40 
41 /**
42  *  This class is used by <code> PxlDocument</code> to maintain pexcel
43  *  workbooks.
44  *
45  *  @author  Martin Maher
46  */
47 public class Workbook implements org.openoffice.xmerge.Document,
48 OfficeConstants {
49 
50     private Vector fonts                = new Vector();
51     private Vector extendedFormats      = new Vector();
52     private Vector worksheets           = new Vector();
53     private Vector boundsheets          = new Vector();
54     private Vector definedNames         = new Vector();
55     private static final CodePage cp;
56     private static final Window1 win1;
57     private static final BeginningOfFile bof;
58     private static final Eof eof;
59     private String fileName;
60 
61     static {
62         cp              = new CodePage();
63         win1            = new Window1();
64         bof             = new BeginningOfFile(true);
65         eof             = new Eof();
66     }
67 
68 
69     /**
70      * Constructs a pocket Excel Workbook with the name of the file passed in
71      * as an argument. Also fills out a basic header block containing the
72      * minimum number of objects that can be created at this time.
73      *
74      * @param   name    Name of the Pocket Excel Data file. (excluding the file
75      *                  extension)
76      */
Workbook(String name)77     public Workbook(String name) throws IOException {
78         fileName = name + PocketExcelConstants.FILE_EXTENSION;
79         Format defaultFormat = new Format();
80         FontDescription fd = new FontDescription(defaultFormat);
81         fonts.add(fd);
82         ExtendedFormat xf = new ExtendedFormat(0, defaultFormat);
83         extendedFormats.add(xf);
84     }
85 
86     /**
87      * Constructs a pocket Excel Workbook from the
88      * <code>InputStream</code> and assigns it the document name passed in
89      *
90      * @param   is InputStream containing a Pocket Excel Data file.
91      */
Workbook(String name, InputStream is)92     public Workbook(String name, InputStream is) throws IOException {
93         read(is);
94         fileName = name;
95     }
96 
97     /**
98      *  Writes the current workbook to the <code>Outputstream</code>
99      *
100      * @param   os The destination outputstream
101      */
write(OutputStream os)102     public void write(OutputStream os) throws IOException {
103         bof.write(os);
104         cp.write(os);
105         for(Enumeration e = definedNames.elements();e.hasMoreElements();) {
106             DefinedName dn = (DefinedName) e.nextElement();
107             dn.write(os);
108         }
109         win1.write(os);
110         for(Enumeration e = fonts.elements();e.hasMoreElements();) {
111             FontDescription fd = (FontDescription) e.nextElement();
112             fd.write(os);
113         }
114         for(Enumeration e = extendedFormats.elements();e.hasMoreElements();) {
115             ExtendedFormat xf = (ExtendedFormat) e.nextElement();
116             xf.write(os);
117         }
118         for(Enumeration e = boundsheets.elements();e.hasMoreElements();) {
119             BoundSheet bs = (BoundSheet) e.nextElement();
120             bs.write(os);
121         }
122         eof.write(os);
123 
124         for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
125             Worksheet ws = (Worksheet) e.nextElement();
126             ws.write(os);
127         }
128     }
129 
130     /**
131      *  Reads a workbook from the <code>InputStream</code> and constructs a
132      *  workbook object from it
133      *
134      * @param   is InputStream containing a Pocket Excel Data file.
135      */
read(InputStream is)136     public void read(InputStream is) throws IOException {
137 
138         boolean done = false;
139 
140         int b = 0;
141         while (!done)
142         {
143             b = is.read();
144             if (b == -1)
145             {
146                 Debug.log(Debug.TRACE,"End of file reached");
147                 break;
148             }
149 
150             switch (b)
151             {
152                 case PocketExcelConstants.DEFINED_NAME:
153                     Debug.log(Debug.TRACE,"NAME: Defined Name (18h)");
154                     DefinedName dn = new DefinedName(is, this);
155                     definedNames.add(dn);
156                     break;
157 
158                 case PocketExcelConstants.BOF_RECORD:
159                     Debug.log(Debug.TRACE,"BOF Record");
160                     bof.read(is);
161                     break;
162 
163                 case PocketExcelConstants.EOF_MARKER:
164                     Debug.log(Debug.TRACE,"EOF Marker");
165                     eof.read(is);
166                     Worksheet ws = new Worksheet(this);
167                     while(ws.read(is)) {
168                         worksheets.add(ws);
169                         ws = new Worksheet(this);
170                     }
171                     break;
172 
173                 case PocketExcelConstants.FONT_DESCRIPTION:
174                     Debug.log(Debug.TRACE,"FONT: Font Description (31h)");
175                     FontDescription fd = new FontDescription(is);
176                     fonts.add(fd);
177                     break;
178 
179                 case PocketExcelConstants.WINDOW_INFO:
180                     Debug.log(Debug.TRACE,"WINDOW1: Window Information (3Dh) [PXL 2.0]");
181                     win1.read(is);
182                     break;
183 
184                 case PocketExcelConstants.CODEPAGE:
185                     Debug.log(Debug.TRACE,"CODEPAGE : Codepage and unknown fields (42h)");
186                     cp.read(is);
187                     break;
188 
189                 case PocketExcelConstants.BOUND_SHEET:
190                     Debug.log(Debug.TRACE,"BOUNDSHEET: Sheet Information (85h)");
191                     BoundSheet bs = new BoundSheet(is);
192                     boundsheets.add(bs);
193                     break;
194 
195                 case PocketExcelConstants.EXTENDED_FORMAT:
196                     Debug.log(Debug.TRACE,"XF: Extended Format (E0h) [PXL 2.0]");
197                     ExtendedFormat xf = new ExtendedFormat(is);
198                     extendedFormats.add(xf);
199                     break;
200 
201                 default:
202                     b = is.read();
203                     break;
204             }
205 
206         }
207         is.close();
208     }
209 
210     /**
211      *  Adds a font record to the workbook
212      *
213      * @param   f the font record to add
214      */
addFont(FontDescription f)215     public int addFont(FontDescription f) {
216 
217         boolean alreadyExists = false;
218         int i = 0;
219 
220         for(Enumeration e = fonts.elements();e.hasMoreElements();) {
221             FontDescription fd = (FontDescription) e.nextElement();
222             if(fd.compareTo(f)) {
223                 alreadyExists = true;
224                 break;
225             } else {
226                 i++;
227             }
228         }
229 
230         if(!alreadyExists)
231                 fonts.add(f);
232 
233         return i;
234     }
235 
236     /**
237      *  Adds a ExtendedFormat record to the workbook
238      *
239      * @param   fmt the font record to add
240      */
addExtendedFormat(Format fmt)241     public int addExtendedFormat(Format fmt) throws IOException {
242 
243         FontDescription fd = new FontDescription(fmt);
244         int ixfnt = addFont(fd);
245         ExtendedFormat xf = new ExtendedFormat(ixfnt, fmt);
246 
247         boolean alreadyExists = false;
248         int i = 0;
249 
250         for(Enumeration e = extendedFormats.elements();e.hasMoreElements();) {
251             ExtendedFormat currentXF = (ExtendedFormat) e.nextElement();
252             if(xf.compareTo(currentXF)) {
253                 alreadyExists = true;
254                 break;
255             } else if(!alreadyExists) {
256                 i++;
257             }
258         }
259 
260         if(!alreadyExists)
261             extendedFormats.add(xf);
262 
263         return i;
264     }
265 
266     /**
267      *  Gets a worksheet at a particular index from mthe current workbook.
268      *
269      * @param   index the index of the worksheet to retrieve
270      */
getWorksheet(int index)271     public Worksheet getWorksheet(int index) {
272 
273         return ((Worksheet) worksheets.elementAt(index));
274     }
275 
276     /**
277      * Returns a FontDescription indictated by the
278      * index parameter passed in to the method
279      *
280      * @param ixfnt index to the FontDescriptions, this is a 0 based index
281      * @return FontDescription indexed by ixfe
282      */
getFontDescription(int ixfnt)283     public FontDescription getFontDescription(int ixfnt) {
284 
285         return (FontDescription) fonts.elementAt(ixfnt);
286     }
287 
288     /**
289      * Returns a ExtendedFormat indictated by the
290      * index parameter passed in to the method
291      *
292      * @param ixfe index to the FontDescriptions, this is a 0 based index
293      * @return FontDescription indexed by ixfe
294      */
getExtendedFormat(int ixfe)295     public ExtendedFormat getExtendedFormat(int ixfe) {
296 
297         return (ExtendedFormat) extendedFormats.elementAt(ixfe);
298     }
299 
300     /**
301      * Returns an enumeration of DefinedNames for this workbook
302      *
303      * @return Enumeration for the DefinedNames
304      */
getDefinedNames()305     public Enumeration getDefinedNames() {
306 
307         return definedNames.elements();
308     }
309 
310     /**
311      * Returns an enumeration of <code>Settings</code> for this workbook
312      *
313      * @return Enumeration of <code>Settings</code>
314      */
getSettings()315     public BookSettings getSettings() {
316 
317         Vector settingsVector = new Vector();
318         int index = 0;
319         for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
320             Worksheet ws = (Worksheet) e.nextElement();
321             SheetSettings s = ws.getSettings();
322             s.setSheetName(getSheetName(index++));
323             settingsVector.add(s);
324         }
325         BookSettings bs = new BookSettings(settingsVector);
326         String activeSheetName = getSheetName(win1.getActiveSheet());
327         bs.setActiveSheet(activeSheetName);
328         return bs;
329     }
330 
331     /**
332      * Returns a <code>Vector</code> containing all the worksheet Names
333      *
334      * @return a <code>Vector</code> containing all the worksheet Names
335      */
getWorksheetNames()336     public Vector getWorksheetNames() {
337 
338         Vector wsNames = new Vector();
339 
340         for(int i = 0;i < boundsheets.size();i++) {
341             wsNames.add(getSheetName(i));
342         }
343 
344         return wsNames;
345     }
346 
347     /**
348      * Returns the name of the worksheet at the specified index
349      *
350      * @return a <code>String</code> containing the name of the worksheet
351      */
getSheetName(int index)352     public String getSheetName(int index) {
353         BoundSheet bs = (BoundSheet) boundsheets.elementAt(index);
354 
355         return bs.getSheetName();
356     }
357 
358     /**
359      * Adds a <code>Worksheet</code> to the workbook.
360      *
361      * @param name the name of the <code>Worksheet</code> to be added
362      */
addWorksheet(String name)363     public void addWorksheet(String name) throws IOException {
364 
365         BoundSheet bs = new BoundSheet(name);
366         boundsheets.add(bs);
367 
368         Worksheet ws = new Worksheet();
369         worksheets.add(ws);
370     }
371 
372     /**
373      * Adds a cell to the current worksheet.
374      *
375      */
addCell(int row,int col, Format fmt, String cellContents)376     public void addCell(int row,int col, Format fmt, String cellContents)
377     throws IOException {
378 
379         Worksheet currentWS = (Worksheet) worksheets.elementAt(worksheets.size()-1);
380         int ixfe = addExtendedFormat(fmt);
381 
382         String category = fmt.getCategory();
383 
384         // Now the formatting is out of the way add the cell
385         Debug.log(Debug.TRACE,"Cell Format: " + fmt);
386         Debug.log(Debug.TRACE,"Row : " + row);
387         Debug.log(Debug.TRACE,"Col : " + col);
388         if(cellContents.startsWith("=")) {
389             try {
390                 Formula f = new Formula(row, col, cellContents, ixfe, fmt, this);
391                 currentWS.addCell(f);
392                 if(category.equalsIgnoreCase(CELLTYPE_STRING)) {
393                     StringValue sv = new StringValue(fmt.getValue());
394                     currentWS.addCell(sv);
395                 }
396             } catch(Exception e) {
397                 Debug.log(Debug.TRACE, "Parsing Exception thrown : " + e.getMessage());
398                 BoolErrCell errorCell = new BoolErrCell(row, col, ixfe, 0x2A, 1);
399                 currentWS.addCell(errorCell);
400             }
401         } else if(category.equalsIgnoreCase(OfficeConstants.CELLTYPE_FLOAT)) {
402             try {
403                 FloatNumber num = new FloatNumber(row, col, cellContents, ixfe);
404                 currentWS.addCell(num);
405             } catch(Exception e) {
406                 Debug.log(Debug.TRACE,"Error could not parse Float " + cellContents);
407                 LabelCell lc = new LabelCell(row, col, cellContents, ixfe);
408                 currentWS.addCell(lc);
409             }
410         } else {
411             if(cellContents.length()==0) {
412                 Debug.log(Debug.TRACE, "Blank Cell");
413                 BlankCell b = new BlankCell(row, col, ixfe);
414                 currentWS.addCell(b);
415             } else {
416                 Debug.log(Debug.TRACE, "Label Cell : " + cellContents);
417                 LabelCell lc = new LabelCell(row, col, cellContents, ixfe);
418                 currentWS.addCell(lc);  // three because we assume the last three
419                                         // Records in any worksheet is the selection,
420                                         // window2 and eof Records
421             }
422         }
423     }
424 
425     /**
426      * Will create a number of ColInfo records based on the column widths
427      * based in.
428      *
429      * @param   columnRows <code>Vector</code> of <code>ColumnRowInfo</code>
430      */
addColInfo(Vector columnRows)431     public void addColInfo(Vector columnRows) throws IOException {
432 
433         Worksheet currentWS = (Worksheet) worksheets.elementAt(worksheets.size()-1);
434 
435         int nCols = 0;
436         int nRows = 0;
437 
438         Debug.log(Debug.TRACE,"Workbook: addColInfo()");
439         for(Enumeration e = columnRows.elements();e.hasMoreElements();) {
440             ColumnRowInfo cri =(ColumnRowInfo) e.nextElement();
441             int ixfe = 0;
442             int size = cri.getSize();
443             int repeated = cri.getRepeated();
444             if(cri.isColumn()) {
445                 Debug.log(Debug.TRACE,"Workbook: adding ColInfo width = " + size);
446                 ColInfo newColInfo = new ColInfo(   nCols,
447                                                     nCols+repeated-1,
448                                                     size, ixfe);
449                 currentWS.addCol(newColInfo);
450                 nCols += repeated;
451             } else if(cri.isRow()) {
452 
453                 Debug.log(Debug.TRACE,"Workbook: adding Row Height = " + size);
454                 if(!cri.isDefaultSize()) {
455                     for(int i=0;i<repeated;i++) {
456                         Row newRow = new Row(nRows++, size, cri.isUserDefined());
457                         currentWS.addRow(newRow);
458                     }
459                 } else {
460                     // If it is the Default Row we don't need to add it
461                     nRows += repeated;
462                 }
463 
464             }
465         }
466     }
467 
addNameDefinition(NameDefinition nameDefinition)468     public void addNameDefinition(NameDefinition nameDefinition) throws IOException {
469 
470         DefinedName dn = new DefinedName(nameDefinition, this);
471         definedNames.add(dn);
472     }
473 
474     /**
475      * Adds the <code>BookSettings</code> for this workbook.
476      *
477      * @param book the <code>BookSettings</code> to add
478      */
addSettings(BookSettings book)479     public void addSettings(BookSettings book) throws IOException {
480 
481         int index = 0;
482         Vector sheetSettings = book.getSheetSettings();
483         String activeSheetName = book.getActiveSheet();
484 
485         for(Enumeration e = worksheets.elements();e.hasMoreElements();) {
486             Worksheet ws = (Worksheet) e.nextElement();
487             String name = getSheetName(index++);
488             if(activeSheetName.equals(name)) {
489                 win1.setActiveSheet(index-1);
490             }
491             for(Enumeration eSettings = sheetSettings.elements();eSettings.hasMoreElements();) {
492                 SheetSettings s = (SheetSettings) eSettings.nextElement();
493                 if(name.equals(s.getSheetName())) {
494                     ws.addSettings(s);
495                 }
496             }
497         }
498     }
499 
500     /**
501      * Return the filename of the pxl document without the file extension
502      *
503      * @return filename without the file extension
504      */
getName()505     public String getName() {
506 
507         // We have to strip off the file extension
508         int end = fileName.lastIndexOf(".");
509         String name;
510         if( end >= 0)   // check in case the filename is already stripped
511             name = fileName.substring(0, end);
512         else
513             name = fileName;
514 
515         return name;
516     }
517 
518     /**
519      * Returns the filename of the pxl document with the file extension
520      *
521      * @return filename with the file extension
522      */
getFileName()523     public String getFileName() {
524 
525         return fileName;
526     }
527 
528 }
529