KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jxl > write > biff > WritableWorkbookImpl


1 /*********************************************************************
2 *
3 * Copyright (C) 2002 Andrew Khan
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 ***************************************************************************/

19
20 package jxl.write.biff;
21
22 import java.util.Iterator JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.HashMap JavaDoc;
25 import java.io.FileOutputStream JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28
29 import common.Assert;
30 import common.Logger;
31
32 import jxl.Workbook;
33 import jxl.Sheet;
34 import jxl.Range;
35 import jxl.WorkbookSettings;
36 import jxl.write.WritableWorkbook;
37 import jxl.write.WritableSheet;
38 import jxl.write.WritableCell;
39 import jxl.biff.RangeImpl;
40 import jxl.biff.IntegerHelper;
41 import jxl.biff.Fonts;
42 import jxl.biff.CountryCode;
43 import jxl.biff.FormattingRecords;
44 import jxl.biff.IndexMapping;
45 import jxl.biff.WorkbookMethods;
46 import jxl.read.biff.WorkbookParser;
47 import jxl.biff.formula.ExternalSheet;
48 import jxl.format.Colour;
49 import jxl.format.RGB;
50 import jxl.biff.drawing.DrawingGroup;
51 import jxl.biff.drawing.DrawingGroupObject;
52 import jxl.biff.drawing.Drawing;
53 import jxl.biff.drawing.Origin;
54
55
56 /**
57  * A writable workbook
58  */

59 public class WritableWorkbookImpl extends WritableWorkbook
60   implements ExternalSheet, WorkbookMethods
61 {
62   /**
63    * The logger
64    */

65   private static Logger logger = Logger.getLogger(WritableWorkbookImpl.class);
66
67   /**
68    * The list of formats available within this workbook
69    */

70   private FormattingRecords formatRecords;
71   /**
72    * The output file to write the workbook to
73    */

74   private File outputFile;
75   /**
76    * The list of sheets within this workbook
77    */

78   private ArrayList JavaDoc sheets;
79   /**
80    * The list of fonts available within this workbook
81    */

82   private Fonts fonts;
83   /**
84    * The list of external sheets, used by cell references in formulas
85    */

86   private ExternalSheetRecord externSheet;
87
88   /**
89    * The supbook records
90    */

91   private ArrayList JavaDoc supbooks;
92
93   /**
94    * The name records
95    */

96   private ArrayList JavaDoc names;
97
98   /**
99    * A lookup hash map of the name records
100    */

101   private HashMap JavaDoc nameRecords;
102
103   /**
104    * The shared strings used by this workbook
105    */

106   private SharedStrings sharedStrings;
107
108   /**
109    * Indicates whether or not the output stream should be closed. This
110    * depends on whether this Workbook was created with an output stream,
111    * or a flat file (flat file closes the stream
112    */

113   private boolean closeStream;
114
115   /**
116    * The workbook protection flag
117    */

118   private boolean wbProtected;
119
120   /**
121    * The settings for the workbook
122    */

123   private WorkbookSettings settings;
124
125   /**
126    * The list of cells for the entire workbook which need to be updated
127    * following a row/column insert or remove
128    */

129   private ArrayList JavaDoc rcirCells;
130
131   /**
132    * The drawing group
133    */

134   private DrawingGroup drawingGroup;
135
136   /**
137    * The common workbook styles
138    */

139   private Styles styles;
140
141   /**
142    * Contains macros flag
143    */

144   private boolean containsMacros;
145
146   /**
147    * The buttons property set
148    */

149   private ButtonPropertySetRecord buttonPropertySet;
150
151   /**
152    * The country record, initialised when copying a workbook
153    */

154   private CountryRecord countryRecord;
155
156   /**
157    * Constructor. Writes the workbook direct to the existing output stream
158    *
159    * @exception IOException
160    * @param os the output stream
161    * @param cs TRUE if the workbook should close the output stream, FALSE
162    * @param ws the configuration for this workbook
163    * otherwise
164    */

165   public WritableWorkbookImpl(OutputStream JavaDoc os, boolean cs, WorkbookSettings ws)
166     throws IOException JavaDoc
167   {
168     super();
169     outputFile = new File(os, ws, null);
170     sheets = new ArrayList JavaDoc();
171     sharedStrings = new SharedStrings();
172     nameRecords = new HashMap JavaDoc();
173     closeStream = cs;
174     wbProtected = false;
175     containsMacros = false;
176     settings = ws;
177     rcirCells = new ArrayList JavaDoc();
178     styles = new Styles();
179
180     // Reset the statically declared styles. Thanks to Brendan for this
181
WritableWorkbook.ARIAL_10_PT.uninitialize();
182     WritableWorkbook.HYPERLINK_FONT.uninitialize();
183     WritableWorkbook.NORMAL_STYLE.uninitialize();
184     WritableWorkbook.HYPERLINK_STYLE.uninitialize();
185     WritableWorkbook.HIDDEN_STYLE.uninitialize();
186     DateRecord.defaultDateFormat.uninitialize();
187
188     WritableFonts wf = new WritableFonts(this);
189     fonts = wf;
190
191     WritableFormattingRecords wfr = new WritableFormattingRecords(fonts,
192                                                                   styles);
193     formatRecords = wfr;
194   }
195
196   /**
197    * A pseudo copy constructor. Takes the handles to the font and formatting
198    * records
199    *
200    * @exception IOException
201    * @param w the workbook to copy
202    * @param os the output stream to write the data to
203    * @param cs TRUE if the workbook should close the output stream, FALSE
204    * @param ws the configuration for this workbook
205    */

206   public WritableWorkbookImpl(OutputStream JavaDoc os,
207                               Workbook w,
208                               boolean cs,
209                               WorkbookSettings ws) throws IOException JavaDoc
210   {
211     super();
212     WorkbookParser wp = (WorkbookParser) w;
213
214     // Reset the statically declared styles. Thanks to Brendan for this
215
WritableWorkbook.ARIAL_10_PT.uninitialize();
216     WritableWorkbook.HYPERLINK_FONT.uninitialize();
217     WritableWorkbook.NORMAL_STYLE.uninitialize();
218     WritableWorkbook.HYPERLINK_STYLE.uninitialize();
219     WritableWorkbook.HIDDEN_STYLE.uninitialize();
220     DateRecord.defaultDateFormat.uninitialize();
221
222     closeStream = cs;
223     sheets = new ArrayList JavaDoc();
224     sharedStrings = new SharedStrings();
225     nameRecords = new HashMap JavaDoc();
226     fonts = wp.getFonts();
227     formatRecords = wp.getFormattingRecords();
228     wbProtected = false;
229     settings = ws;
230     rcirCells = new ArrayList JavaDoc();
231     styles = new Styles();
232     outputFile = new File(os, ws, wp.getCompoundFile());
233
234     containsMacros = false;
235     if (!ws.getPropertySetsDisabled())
236     {
237       containsMacros = wp.containsMacros();
238     }
239
240     // Copy the country settings
241
if (wp.getCountryRecord() != null)
242     {
243       countryRecord = new CountryRecord(wp.getCountryRecord());
244     }
245
246     // Copy any external sheets
247
if (wp.getExternalSheetRecord() != null)
248     {
249       externSheet = new ExternalSheetRecord(wp.getExternalSheetRecord());
250
251       // Get the associated supbooks
252
jxl.read.biff.SupbookRecord[] readsr = wp.getSupbookRecords();
253       supbooks = new ArrayList JavaDoc(readsr.length);
254
255       for (int i = 0; i < readsr.length; i++)
256       {
257         supbooks.add(new SupbookRecord(readsr[i], settings));
258       }
259     }
260
261     // Copy any drawings. These must be present before we try and copy
262
// the images from the read workbook
263
if (wp.getDrawingGroup() != null)
264     {
265       drawingGroup = new DrawingGroup(wp.getDrawingGroup());
266     }
267
268     // Copy the property set references
269
if (containsMacros && wp.getButtonPropertySet() != null)
270     {
271       buttonPropertySet = new ButtonPropertySetRecord
272         (wp.getButtonPropertySet());
273     }
274
275     // Copy any names
276
if (!settings.getNamesDisabled())
277     {
278       jxl.read.biff.NameRecord[] na = wp.getNameRecords();
279       names = new ArrayList JavaDoc(na.length);
280       
281       for (int i = 0; i < na.length; i++)
282       {
283         if (na[i].isBiff8())
284         {
285           NameRecord n = new NameRecord(na[i], i);
286           names.add(n);
287           String JavaDoc name = n.getName();
288           nameRecords.put(name, n);
289         }
290         else
291         {
292           logger.warn("Cannot copy Biff7 name records - ignoring");
293         }
294       }
295     }
296     
297     copyWorkbook(w);
298
299     // The copy process may have caused some critical fields in the
300
// read drawing group to change. Make sure these updates are reflected
301
// in the writable drawing group
302
if (drawingGroup != null)
303     {
304       drawingGroup.updateData(wp.getDrawingGroup());
305     }
306   }
307
308   /**
309    * Gets the sheets within this workbook. Use of this method for
310    * large worksheets can cause performance problems.
311    *
312    * @return an array of the individual sheets
313    */

314   public WritableSheet[] getSheets()
315   {
316     WritableSheet[] sheetArray = new WritableSheet[getNumberOfSheets()];
317     
318     for (int i = 0 ; i < getNumberOfSheets() ; i++)
319     {
320       sheetArray[i] = getSheet(i);
321     }
322     return sheetArray;
323   }
324
325   /**
326    * Gets the sheet names
327    *
328    * @return an array of strings containing the sheet names
329    */

330   public String JavaDoc[] getSheetNames()
331   {
332     String JavaDoc[] sheetNames = new String JavaDoc[getNumberOfSheets()];
333
334     for (int i = 0 ; i < sheetNames.length ; i++)
335     {
336       sheetNames[i] = getSheet(i).getName();
337     }
338
339     return sheetNames;
340   }
341
342   /**
343    * Interface method from WorkbookMethods - gets the specified
344    * sheet within this workbook
345    *
346    * @param index the zero based index of the required sheet
347    * @return The sheet specified by the index
348    */

349   public Sheet getReadSheet(int index)
350   {
351     return getSheet(index);
352   }
353
354   /**
355    * Gets the specified sheet within this workbook
356    *
357    * @param index the zero based index of the reQuired sheet
358    * @return The sheet specified by the index
359    */

360   public WritableSheet getSheet(int index)
361   {
362     return (WritableSheet) sheets.get(index);
363   }
364
365   /**
366    * Gets the sheet with the specified name from within this workbook
367    *
368    * @param name the sheet name
369    * @return The sheet with the specified name, or null if it is not found
370    */

371   public WritableSheet getSheet(String JavaDoc name)
372   {
373     // Iterate through the boundsheet records
374
boolean found = false;
375     Iterator JavaDoc i = sheets.iterator();
376     WritableSheet s = null;
377
378     while (i.hasNext() && !found)
379     {
380       s = (WritableSheet) i.next();
381       
382       if (s.getName().equals(name))
383       {
384         found = true;
385       }
386     }
387
388     return found ? s : null;
389   }
390
391   /**
392    * Returns the number of sheets in this workbook
393    *
394    * @return the number of sheets in this workbook
395    */

396   public int getNumberOfSheets()
397   {
398     return sheets.size();
399   }
400
401   /**
402    * Closes this workbook, and frees makes any memory allocated available
403    * for garbage collection
404    *
405    * @exception IOException
406    * @exception JxlWriteException
407    */

408   public void close() throws IOException JavaDoc, JxlWriteException
409   {
410     outputFile.close(closeStream);
411   }
412
413   /**
414    * Sets a new output file. This allows the smae workbook to be
415    * written to various different output files without having to
416    * read in any templates again
417    *
418    * @param fileName the file name
419    * @exception IOException
420    */

421   public void setOutputFile(java.io.File JavaDoc fileName) throws IOException JavaDoc
422   {
423     FileOutputStream JavaDoc fos = new FileOutputStream JavaDoc(fileName);
424     outputFile.setOutputFile(fos);
425   }
426
427
428   /**
429    * The internal method implementation for creating new sheets
430    *
431    * @param name
432    * @param index
433    * @param handleRefs flag indicating whether or not to handle external
434    * sheet references
435    * @return
436    */

437   private WritableSheet createSheet(String JavaDoc name, int index,
438                                     boolean handleRefs)
439   {
440     WritableSheet w = new WritableSheetImpl(name,
441                                             outputFile,
442                                             formatRecords,
443                                             sharedStrings,
444                                             settings,
445                                             this);
446
447     int pos = index;
448
449     if (index <= 0)
450     {
451       pos = 0;
452       sheets.add(0, w);
453     }
454     else if (index > sheets.size())
455     {
456       pos = sheets.size();
457       sheets.add(w);
458     }
459     else
460     {
461       sheets.add(index, w);
462     }
463
464     if (handleRefs && externSheet != null)
465     {
466       externSheet.sheetInserted(pos);
467     }
468
469     if (supbooks != null && supbooks.size() > 0)
470     {
471       SupbookRecord supbook = (SupbookRecord) supbooks.get(0);
472       if (supbook.getType() == SupbookRecord.INTERNAL)
473       {
474         supbook.adjustInternal(sheets.size());
475       }
476     }
477
478     return w;
479   }
480
481   /**
482    * Creates a new sheet within the workbook, at the specified position.
483    * The new sheet is inserted at the specified position, or prepended/appended
484    * to the list of sheets if the index specified is somehow inappropriate
485    *
486    * @param name the name of the new sheet
487    * @param index the index at which to add the sheet
488    * @return the created sheet
489    */

490   public WritableSheet createSheet(String JavaDoc name, int index)
491   {
492     return createSheet(name, index, true);
493   }
494
495   /**
496    * Removes a sheet from this workbook, the other sheets indices being
497    * altered accordingly. If the sheet referenced by the index
498    * does not exist, then no action is taken.
499    *
500    * @param index the index of the sheet to remove
501    */

502   public void removeSheet(int index)
503   {
504     int pos = index;
505     if (index <= 0)
506     {
507       pos = 0;
508       sheets.remove(0);
509     }
510     else if (index >= sheets.size())
511     {
512       pos = sheets.size() - 1;
513       sheets.remove(sheets.size() - 1);
514     }
515     else
516     {
517       sheets.remove(index);
518     }
519
520     if (externSheet != null)
521     {
522       externSheet.sheetRemoved(pos);
523     }
524
525     if (supbooks != null && supbooks.size() > 0)
526     {
527       SupbookRecord supbook = (SupbookRecord) supbooks.get(0);
528       if (supbook.getType() == SupbookRecord.INTERNAL)
529       {
530         supbook.adjustInternal(sheets.size());
531       }
532     }
533
534     if (names != null && names.size() > 0)
535     {
536       for (int i=0; i< names.size();i++)
537       {
538         NameRecord n = (NameRecord) names.get(i);
539         int oldRef = n.getSheetRef();
540         if(oldRef == (pos+1))
541         {
542           n.setSheetRef(0); // make a global name reference
543
}
544         else if (oldRef > (pos+1))
545         {
546           if(oldRef < 1)
547           {
548             oldRef = 1;
549           }
550           n.setSheetRef(oldRef-1); // move one sheet
551
}
552       }
553     }
554   }
555
556   /**
557    * Moves the specified sheet within this workbook to another index
558    * position.
559    *
560    * @param fromIndex the zero based index of the reQuired sheet
561    * @param toIndex the zero based index of the reQuired sheet
562    * @return the sheet that has been moved
563    */

564   public WritableSheet moveSheet(int fromIndex, int toIndex)
565   {
566     // Handle dodgy index
567
fromIndex = Math.max(fromIndex, 0);
568     fromIndex = Math.min(fromIndex, sheets.size() - 1);
569     toIndex = Math.max(toIndex, 0);
570     toIndex = Math.min(toIndex, sheets.size() - 1);
571
572     WritableSheet sheet= (WritableSheet)sheets.remove(fromIndex);
573     sheets.add(toIndex, sheet);
574     
575     return sheet;
576   }
577
578   /**
579    * Writes out this sheet to the output file. First it writes out
580    * the standard workbook information required by excel, before calling
581    * the write method on each sheet individually
582    *
583    * @exception IOException
584    */

585   public void write() throws IOException JavaDoc
586   {
587     // Check the merged records. This has to be done before the
588
// globals are written out because some more XF formats might be created
589
WritableSheetImpl wsi = null;
590     for (int i = 0; i < getNumberOfSheets(); i++)
591     {
592       wsi = (WritableSheetImpl) getSheet(i);
593       wsi.checkMergedBorders();
594     }
595
596     // Rationalize all the XF and number formats
597
if (!settings.getRationalizationDisabled())
598     {
599       rationalize();
600     }
601
602     // Write the workbook globals
603
BOFRecord bof = new BOFRecord(BOFRecord.workbookGlobals);
604     outputFile.write(bof);
605
606     InterfaceHeaderRecord ihr = new InterfaceHeaderRecord();
607     outputFile.write(ihr);
608
609     MMSRecord mms = new MMSRecord(0,0);
610     outputFile.write(mms);
611
612     InterfaceEndRecord ier = new InterfaceEndRecord();
613     outputFile.write(ier);
614
615     WriteAccessRecord wr = new WriteAccessRecord();
616     outputFile.write(wr);
617
618     CodepageRecord cp = new CodepageRecord();
619     outputFile.write(cp);
620
621     DSFRecord dsf = new DSFRecord();
622     outputFile.write(dsf);
623
624     TabIdRecord tabid = new TabIdRecord(getNumberOfSheets());
625     outputFile.write(tabid);
626
627     if (containsMacros)
628     {
629       ObjProjRecord objproj = new ObjProjRecord();
630       outputFile.write(objproj);
631     }
632
633     if (buttonPropertySet != null)
634     {
635       outputFile.write(buttonPropertySet);
636     }
637
638     FunctionGroupCountRecord fgcr = new FunctionGroupCountRecord();
639     outputFile.write(fgcr);
640
641     // do not support password protected workbooks
642
WindowProtectRecord wpr = new WindowProtectRecord(false);
643     outputFile.write(wpr);
644
645     ProtectRecord pr = new ProtectRecord(wbProtected);
646     outputFile.write(pr);
647
648     PasswordRecord pw = new PasswordRecord(null);
649     outputFile.write(pw);
650
651     Prot4RevRecord p4r = new Prot4RevRecord(false);
652     outputFile.write(p4r);
653
654     Prot4RevPassRecord p4rp = new Prot4RevPassRecord();
655     outputFile.write(p4rp);
656
657     Window1Record w1r = new Window1Record();
658     outputFile.write(w1r);
659
660     BackupRecord bkr = new BackupRecord(false);
661     outputFile.write(bkr);
662
663     HideobjRecord ho = new HideobjRecord(false);
664     outputFile.write(ho);
665     
666     NineteenFourRecord nf = new NineteenFourRecord(false);
667     outputFile.write(nf);
668
669     PrecisionRecord pc = new PrecisionRecord(false);
670     outputFile.write(pc);
671
672     RefreshAllRecord rar = new RefreshAllRecord(false);
673     outputFile.write(rar);
674
675     BookboolRecord bb = new BookboolRecord(true);
676     outputFile.write(bb);
677
678     // Write out all the fonts used
679
fonts.write(outputFile);
680
681     // Write out the cell formats used within this workbook
682
formatRecords.write(outputFile);
683
684     // Write out the palette, if it exists
685
if (formatRecords.getPalette() != null)
686     {
687       outputFile.write(formatRecords.getPalette());
688     }
689
690     // Write out the uses elfs record
691
UsesElfsRecord uer = new UsesElfsRecord();
692     outputFile.write(uer);
693     
694     // Write out the boundsheet records. Keep a handle to each one's
695
// position so we can write in the stream offset later
696
int[] boundsheetPos = new int[getNumberOfSheets()];
697     Sheet sheet = null;
698
699     for (int i = 0; i < getNumberOfSheets(); i++)
700     {
701       boundsheetPos[i] = outputFile.getPos();
702       sheet = getSheet(i);
703       BoundsheetRecord br = new BoundsheetRecord
704         (sheet.getName());
705       if (sheet.getSettings().isHidden())
706       {
707         br.setHidden();
708       }
709
710       if ( ( (WritableSheetImpl) sheets.get(i)).isChartOnly())
711       {
712         br.setChartOnly();
713       }
714
715       outputFile.write(br);
716     }
717
718     if (countryRecord == null)
719     {
720       CountryCode lang =
721         CountryCode.getCountryCode(settings.getExcelDisplayLanguage());
722       if (lang == CountryCode.UNKNOWN)
723       {
724         logger.warn("Unknown country code " +
725                     settings.getExcelDisplayLanguage() +
726                     " using " + CountryCode.USA.getCode());
727         lang = CountryCode.USA;
728       }
729       CountryCode region =
730         CountryCode.getCountryCode(settings.getExcelRegionalSettings());
731       countryRecord = new CountryRecord(lang, region);
732       if (region == CountryCode.UNKNOWN)
733       {
734         logger.warn("Unknown country code " +
735                     settings.getExcelDisplayLanguage() +
736                     " using " + CountryCode.UK.getCode());
737         region = CountryCode.UK;
738       }
739     }
740
741     outputFile.write(countryRecord);
742
743     // Write out the external sheet record, if it exists
744
if (externSheet != null)
745     {
746       //Write out all the supbook records
747
for (int i = 0; i < supbooks.size() ; i++)
748       {
749         SupbookRecord supbook = (SupbookRecord) supbooks.get(i);
750         outputFile.write(supbook);
751       }
752       outputFile.write(externSheet);
753     }
754
755     // Write out the names, if any exists
756
if (names != null)
757     {
758       for (int i = 0 ; i < names.size() ; i++)
759       {
760         NameRecord n = (NameRecord) names.get(i);
761         outputFile.write(n);
762       }
763     }
764   
765     // Write out the mso drawing group, if it exists
766
if (drawingGroup != null)
767     {
768       drawingGroup.write(outputFile);
769     }
770
771     sharedStrings.write(outputFile);
772
773     EOFRecord eof = new EOFRecord();
774     outputFile.write(eof);
775
776     // If no sheet is identified as being selected, then select
777
// the first one
778
boolean sheetSelected = false;
779     WritableSheetImpl wsheet = null;
780     for (int i = 0 ; i < getNumberOfSheets() && !sheetSelected ; i++)
781     {
782       wsheet = (WritableSheetImpl) getSheet(i);
783       if (wsheet.getSettings().isSelected())
784       {
785         sheetSelected = true;
786       }
787     }
788
789     if (!sheetSelected)
790     {
791       wsheet = (WritableSheetImpl) getSheet(0);
792       wsheet.getSettings().setSelected(true);
793     }
794
795     // Write out the sheets
796
for (int i = 0; i < getNumberOfSheets(); i++)
797     {
798       // first go back and modify the offset we wrote out for the
799
// boundsheet record
800
outputFile.setData
801         (IntegerHelper.getFourBytes(outputFile.getPos()),
802          boundsheetPos[i] + 4);
803
804       wsheet = (WritableSheetImpl) getSheet(i);
805       wsheet.write();
806     }
807   }
808
809   /**
810    * Produces a writable copy of the workbook passed in by
811    * creating copies of each sheet in the specified workbook and adding
812    * them to its own record
813    *
814    * @param w the workbook to copy
815    */

816   private void copyWorkbook(Workbook w)
817   {
818     int numSheets = w.getNumberOfSheets();
819     wbProtected = w.isProtected();
820     Sheet s = null;
821     WritableSheetImpl ws = null;
822     for (int i = 0 ; i < numSheets; i++)
823     {
824       s = w.getSheet(i);
825       ws = (WritableSheetImpl) createSheet(s.getName(),i, false);
826       ws.copy(s);
827     }
828   }
829
830   /**
831    * Copies the specified sheet and places it at the index
832    * specified by the parameter
833    *
834    * @param s the index of the sheet to copy
835    * @param name the name of the new sheet
836    * @param index the position of the new sheet
837    */

838   public void copySheet(int s, String JavaDoc name, int index)
839   {
840     WritableSheet sheet = getSheet(s);
841     WritableSheetImpl ws = (WritableSheetImpl) createSheet(name, index);
842     ws.copy(sheet);
843   }
844
845   /**
846    * Copies the specified sheet and places it at the index
847    * specified by the parameter
848    *
849    * @param s the name of the sheet to copy
850    * @param name the name of the new sheet
851    * @param index the position of the new sheet
852    */

853   public void copySheet(String JavaDoc s, String JavaDoc name, int index)
854   {
855     WritableSheet sheet = getSheet(s);
856     WritableSheetImpl ws = (WritableSheetImpl) createSheet(name, index);
857     ws.copy(sheet);
858   }
859
860   /**
861    * Indicates whether or not this workbook is protected
862    *
863    * @param prot protected flag
864    */

865   public void setProtected(boolean prot)
866   {
867     wbProtected = prot;
868   }
869
870   /**
871    * Rationalizes the cell formats, and then passes the resultant XF index
872    * mappings to each sheet in turn
873    */

874   private void rationalize()
875   {
876     IndexMapping fontMapping = formatRecords.rationalizeFonts();
877     IndexMapping formatMapping = formatRecords.rationalizeDisplayFormats();
878     IndexMapping xfMapping = formatRecords.rationalize(fontMapping,
879                                                            formatMapping);
880
881     WritableSheetImpl wsi = null;
882     for (int i = 0; i < sheets.size(); i++)
883     {
884       wsi = (WritableSheetImpl) sheets.get(i);
885       wsi.rationalize(xfMapping, fontMapping, formatMapping);
886     }
887   }
888
889   /**
890    * Gets the name of the external sheet specified by the index
891    *
892    * @param index the external sheet index
893    * @return the name of the external sheet
894    */

895   public String JavaDoc getExternalSheetName(int index)
896   {
897     int supbookIndex = externSheet.getSupbookIndex(index);
898     SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex);
899     
900     int firstTab = externSheet.getFirstTabIndex(index);
901     
902     if (sr.getType() == SupbookRecord.INTERNAL)
903     {
904       // It's an internal reference - get the name from the sheets list
905
WritableSheet ws = getSheet(firstTab);
906
907       return ws.getName();
908     }
909     else if (sr.getType() == SupbookRecord.EXTERNAL)
910     {
911       String JavaDoc name = sr.getFileName() + sr.getSheetName(firstTab);
912       return name;
913     }
914     
915     // An unknown supbook - return unkown
916
return "[UNKNOWN]";
917   }
918
919   /**
920    * Gets the name of the last external sheet specified by the index
921    *
922    * @param index the external sheet index
923    * @return the name of the external sheet
924    */

925   public String JavaDoc getLastExternalSheetName(int index)
926   {
927     int supbookIndex = externSheet.getSupbookIndex(index);
928     SupbookRecord sr = (SupbookRecord) supbooks.get(supbookIndex);
929     
930     int lastTab = externSheet.getLastTabIndex(index);
931     
932     if (sr.getType() == SupbookRecord.INTERNAL)
933     {
934       // It's an internal reference - get the name from the sheets list
935
WritableSheet ws = getSheet(lastTab);
936
937       return ws.getName();
938     }
939     else if (sr.getType() == SupbookRecord.EXTERNAL)
940     {
941       Assert.verify(false);
942     }
943     
944     // An unknown supbook - return unkown
945
return "[UNKNOWN]";
946   }
947
948   /**
949    * Parsing of formulas is only supported for a subset of the available
950    * biff version, so we need to test to see if this version is acceptable
951    *
952    * @return the BOF record, which
953    */

954   public jxl.read.biff.BOFRecord getWorkbookBof()
955   {
956     return null;
957   }
958
959
960   /**
961    * Gets the index of the external sheet for the name
962    *
963    * @param sheetName
964    * @return the sheet index of the external sheet index
965    */

966   public int getExternalSheetIndex(int index)
967   {
968     if (externSheet == null)
969     {
970       return index;
971     }
972
973     Assert.verify(externSheet != null);
974
975     int firstTab = externSheet.getFirstTabIndex(index);
976
977     return firstTab;
978   }
979
980   /**
981    * Gets the index of the external sheet for the name
982    *
983    * @param sheetName
984    * @return the sheet index of the external sheet index
985    */

986   public int getLastExternalSheetIndex(int index)
987   {
988     if (externSheet == null)
989     {
990       return index;
991     }
992
993     Assert.verify(externSheet != null);
994
995     int lastTab = externSheet.getLastTabIndex(index);
996
997     return lastTab;
998   }
999
1000  /**
1001   * Gets the external sheet index for the sheet name
1002   * @param sheetName
1003   * @return the sheet index or -1 if the sheet could not be found
1004   */

1005  public int getExternalSheetIndex(String JavaDoc sheetName)
1006  {
1007    if (externSheet == null)
1008    {
1009      externSheet = new ExternalSheetRecord();
1010      supbooks = new ArrayList JavaDoc();
1011      supbooks.add(new SupbookRecord(getNumberOfSheets(), settings));
1012    }
1013
1014    // Iterate through the sheets records
1015
boolean found = false;
1016    Iterator JavaDoc i = sheets.iterator();
1017    int sheetpos = 0;
1018    WritableSheetImpl s = null;
1019
1020    while (i.hasNext() && !found)
1021    {
1022      s = (WritableSheetImpl) i.next();
1023      
1024      if (s.getName().equals(sheetName))
1025      {
1026        found = true;
1027      }
1028      else
1029      {
1030        sheetpos++;
1031      }
1032    }
1033
1034    if (found)
1035    {
1036      // Check that the supbook record at position zero is internal and
1037
// contains all the sheets
1038
SupbookRecord supbook = (SupbookRecord) supbooks.get(0);
1039      Assert.verify(supbook.getType() == SupbookRecord.INTERNAL &&
1040                    supbook.getNumberOfSheets() == getNumberOfSheets());
1041      
1042      return externSheet.getIndex(0, sheetpos);
1043    }
1044
1045    // Check for square brackets
1046
int closeSquareBracketsIndex = sheetName.lastIndexOf(']');
1047    int openSquareBracketsIndex = sheetName.lastIndexOf('[');
1048    
1049    if (closeSquareBracketsIndex == -1 ||
1050        openSquareBracketsIndex == -1)
1051    {
1052      return -1;
1053    }
1054
1055    String JavaDoc worksheetName = sheetName.substring(closeSquareBracketsIndex+1);
1056    String JavaDoc workbookName = sheetName.substring(openSquareBracketsIndex+1,
1057                                              closeSquareBracketsIndex);
1058    String JavaDoc path = sheetName.substring(0, openSquareBracketsIndex);
1059    String JavaDoc fileName = path + workbookName;
1060
1061    boolean supbookFound = false;
1062    SupbookRecord externalSupbook = null;
1063    int supbookIndex = -1;
1064    for (int ind = 0; ind < supbooks.size() && !supbookFound ; ind++)
1065    {
1066      externalSupbook = (SupbookRecord) supbooks.get(ind);
1067      if (externalSupbook.getType() == SupbookRecord.EXTERNAL &&
1068          externalSupbook.getFileName().equals(fileName))
1069      {
1070        supbookFound = true;
1071        supbookIndex = ind;
1072      }
1073    }
1074
1075    if (!supbookFound)
1076    {
1077      externalSupbook = new SupbookRecord(fileName, settings);
1078      supbookIndex = supbooks.size();
1079      supbooks.add(externalSupbook);
1080    }
1081    
1082    int sheetIndex = externalSupbook.getSheetIndex(worksheetName);
1083
1084    return externSheet.getIndex(supbookIndex, sheetIndex);
1085  }
1086
1087  /**
1088   * Gets the last external sheet index for the sheet name
1089   * @param sheetName
1090   * @return the sheet index or -1 if the sheet could not be found
1091   */

1092  public int getLastExternalSheetIndex(String JavaDoc sheetName)
1093  {
1094    if (externSheet == null)
1095    {
1096      externSheet = new ExternalSheetRecord();
1097      supbooks = new ArrayList JavaDoc();
1098      supbooks.add(new SupbookRecord(getNumberOfSheets(), settings));
1099    }
1100
1101    // Iterate through the sheets records
1102
boolean found = false;
1103    Iterator JavaDoc i = sheets.iterator();
1104    int sheetpos = 0;
1105    WritableSheetImpl s = null;
1106
1107    while (i.hasNext() && !found)
1108    {
1109      s = (WritableSheetImpl) i.next();
1110      
1111      if (s.getName().equals(sheetName))
1112      {
1113        found = true;
1114      }
1115      else
1116      {
1117        sheetpos++;
1118      }
1119    }
1120
1121    if (!found)
1122    {
1123      return -1;
1124    }
1125
1126    // Check that the supbook record at position zero is internal and contains
1127
// all the sheets
1128
SupbookRecord supbook = (SupbookRecord) supbooks.get(0);
1129    Assert.verify(supbook.getType() == SupbookRecord.INTERNAL &&
1130                  supbook.getNumberOfSheets() == getNumberOfSheets());
1131
1132    return externSheet.getIndex(0, sheetpos);
1133  }
1134
1135  /**
1136   * Sets the RGB value for the specified colour for this workbook
1137   *
1138   * @param c the colour whose RGB value is to be overwritten
1139   * @param r the red portion to set (0-255)
1140   * @param g the green portion to set (0-255)
1141   * @param b the blue portion to set (0-255)
1142   */

1143  public void setColourRGB(Colour c, int r, int g, int b)
1144  {
1145    formatRecords.setColourRGB(c,r,g,b);
1146  }
1147
1148  /**
1149   * Accessor for the RGB value for the specified colour
1150   *
1151   * @return the RGB for the specified colour
1152   */

1153  public RGB getColourRGB(Colour c)
1154  {
1155    return formatRecords.getColourRGB(c);
1156  }
1157
1158  /**
1159   * Gets the name at the specified index
1160   *
1161   * @param index the index into the name table
1162   * @return the name of the cell
1163   */

1164  public String JavaDoc getName(int index)
1165  {
1166    Assert.verify(index >= 0 && index < names.size());
1167    NameRecord n = (NameRecord) names.get(index);
1168    return n.getName();
1169  }
1170
1171  /**
1172   * Gets the index of the name record for the name
1173   *
1174   * @param name
1175   * @return the index in the name table
1176   */

1177  public int getNameIndex(String JavaDoc name)
1178  {
1179    NameRecord nr = (NameRecord) nameRecords.get(name);
1180    return nr != null ? nr.getIndex() : -1;
1181  }
1182
1183  /**
1184   * Adds a cell to workbook wide range of cells which need adjustment
1185   * following a row/column insert or remove
1186   *
1187   * @param f the cell to add to the list
1188   */

1189  void addRCIRCell(CellValue cv)
1190  {
1191    rcirCells.add(cv);
1192  }
1193
1194  /**
1195   * Called when a column is inserted on the specified sheet. Notifies all
1196   * RCIR cells of this change
1197   *
1198   * @param s the sheet on which the column was inserted
1199   * @param col the column number which was inserted
1200   */

1201  void columnInserted(WritableSheetImpl s, int col)
1202  {
1203    int externalSheetIndex = getExternalSheetIndex(s.getName());
1204    for (Iterator JavaDoc i = rcirCells.iterator() ; i.hasNext() ;)
1205    {
1206      CellValue cv = (CellValue) i.next();
1207      cv.columnInserted(s, externalSheetIndex, col);
1208    }
1209  }
1210
1211  /**
1212   * Called when a column is removed on the specified sheet. Notifies all
1213   * RCIR cells of this change
1214   *
1215   * @param s the sheet on which the column was removed
1216   * @param col the column number which was removed
1217   */

1218  void columnRemoved(WritableSheetImpl s, int col)
1219  {
1220    int externalSheetIndex = getExternalSheetIndex(s.getName());
1221    for (Iterator JavaDoc i = rcirCells.iterator() ; i.hasNext() ;)
1222    {
1223      CellValue cv = (CellValue) i.next();
1224      cv.columnRemoved(s, externalSheetIndex, col);
1225    }
1226  }
1227
1228  /**
1229   * Called when a row is inserted on the specified sheet. Notifies all
1230   * RCIR cells of this change
1231   *
1232   * @param s the sheet on which the row was inserted
1233   * @param row the row number which was inserted
1234   */

1235  void rowInserted(WritableSheetImpl s, int row)
1236  {
1237    int externalSheetIndex = getExternalSheetIndex(s.getName());
1238    for (Iterator JavaDoc i = rcirCells.iterator() ; i.hasNext() ;)
1239    {
1240      CellValue cv = (CellValue) i.next();
1241      cv.rowInserted(s, externalSheetIndex, row);
1242    }
1243  }
1244
1245  /**
1246   * Called when a row is removed on the specified sheet. Notifies all
1247   * RCIR cells of this change
1248   *
1249   * @param s the sheet on which the row was removed
1250   * @param row the row number which was removed
1251   */

1252  void rowRemoved(WritableSheetImpl s, int row)
1253  {
1254    int externalSheetIndex = getExternalSheetIndex(s.getName());
1255    for (Iterator JavaDoc i = rcirCells.iterator() ; i.hasNext() ;)
1256    {
1257      CellValue cv = (CellValue) i.next();
1258      cv.rowRemoved(s, externalSheetIndex, row);
1259    }
1260  }
1261
1262  /**
1263   * Gets the named cell from this workbook. If the name refers to a
1264   * range of cells, then the cell on the top left is returned. If
1265   * the name cannot be found, null is returned
1266   *
1267   * @param the name of the cell/range to search for
1268   * @return the cell in the top left of the range if found, NULL
1269   * otherwise
1270   */

1271  public WritableCell findCellByName(String JavaDoc name)
1272  {
1273    NameRecord nr = (NameRecord) nameRecords.get(name);
1274
1275    if (nr == null)
1276    {
1277      return null;
1278    }
1279
1280    NameRecord.NameRange[] ranges = nr.getRanges();
1281
1282    // Go and retrieve the first cell in the first range
1283
int sheetIndex = getExternalSheetIndex(ranges[0].getExternalSheet());
1284    WritableSheet s = getSheet(sheetIndex);
1285    WritableCell cell = s.getWritableCell(ranges[0].getFirstColumn(),
1286                                           ranges[0].getFirstRow());
1287
1288    return cell;
1289  }
1290
1291  /**
1292   * Gets the named range from this workbook. The Range object returns
1293   * contains all the cells from the top left to the bottom right
1294   * of the range.
1295   * If the named range comprises an adjacent range,
1296   * the Range[] will contain one object; for non-adjacent
1297   * ranges, it is necessary to return an array of length greater than
1298   * one.
1299   * If the named range contains a single cell, the top left and
1300   * bottom right cell will be the same cell
1301   *
1302   * @param the name of the cell/range to search for
1303   * @return the range of cells
1304   */

1305  public Range[] findByName(String JavaDoc name)
1306  {
1307    NameRecord nr = (NameRecord) nameRecords.get(name);
1308
1309    if (nr == null)
1310    {
1311      return null;
1312    }
1313
1314    NameRecord.NameRange[] ranges = nr.getRanges();
1315
1316    Range[] cellRanges = new Range[ranges.length];
1317
1318    for (int i = 0; i < ranges.length ; i++)
1319    {
1320      cellRanges[i] = new RangeImpl
1321        (this,
1322         getExternalSheetIndex(ranges[i].getExternalSheet()),
1323         ranges[i].getFirstColumn(),
1324         ranges[i].getFirstRow(),
1325         getLastExternalSheetIndex(ranges[i].getExternalSheet()),
1326         ranges[i].getLastColumn(),
1327         ranges[i].getLastRow());
1328    }
1329
1330    return cellRanges;
1331  }
1332
1333  /**
1334   * Adds a drawing to this workbook
1335   *
1336   * @param d the drawing to add
1337   */

1338  void addDrawing(DrawingGroupObject d)
1339  {
1340    if (drawingGroup == null)
1341    {
1342      drawingGroup = new DrawingGroup(Origin.WRITE);
1343    }
1344
1345    drawingGroup.add(d);
1346  }
1347
1348  /**
1349   * Removes a drawing from this workbook
1350   *
1351   * @param d the drawing to remove
1352   */

1353  void removeDrawing(Drawing d)
1354  {
1355    Assert.verify(drawingGroup != null);
1356
1357    drawingGroup.remove(d);
1358  }
1359
1360  /**
1361   * Accessor for the drawing group
1362   *
1363   * @return the drawing group
1364   */

1365  DrawingGroup getDrawingGroup()
1366  {
1367    return drawingGroup;
1368  }
1369
1370  /**
1371   * Gets the named ranges
1372   *
1373   * @return the list of named cells within the workbook
1374   */

1375  public String JavaDoc[] getRangeNames()
1376  {
1377    String JavaDoc[] n = new String JavaDoc[names.size()];
1378    for (int i = 0 ; i < names.size() ; i++)
1379    {
1380      NameRecord nr = (NameRecord) names.get(i);
1381      n[i] = nr.getName();
1382    }
1383
1384    return n;
1385  }
1386
1387  /**
1388   * Accessor for the common styles
1389   *
1390   * @return the standard styles for this workbook
1391   */

1392  Styles getStyles()
1393  {
1394    return styles;
1395  }
1396
1397  /**
1398   * Add new named area to this workbook with the given information.
1399   *
1400   * @param name name to be created.
1401   * @param sheet sheet containing the name
1402   * @param firstCol first column this name refers to.
1403   * @param firstRow first row this name refers to.
1404   * @param lastCol last column this name refers to.
1405   * @param lastRow last row this name refers to.
1406   */

1407  public void addNameArea(String JavaDoc name,
1408                          WritableSheet sheet,
1409                          int firstCol,
1410                          int firstRow,
1411                          int lastCol,
1412                          int lastRow)
1413  {
1414    if (names == null)
1415    {
1416      names = new ArrayList JavaDoc();
1417    }
1418
1419    int externalSheetIndex = getExternalSheetIndex(sheet.getName());
1420
1421    // Create a new name record.
1422
NameRecord nr =
1423      new NameRecord(name, names.size(),
1424                     externalSheetIndex,
1425                     firstRow, lastRow,
1426                     firstCol, lastCol);
1427    
1428    // Add new name to name array.
1429
names.add(nr);
1430    
1431    // Add new name to name hash table.
1432
nameRecords.put(name, nr);
1433  }
1434
1435  /**
1436   * Accessor for the workbook settings
1437   */

1438  WorkbookSettings getSettings()
1439  {
1440    return settings;
1441  }
1442}
1443
1444
1445
1446
1447
1448
Popular Tags