1 /*********************************************************************
2 *
3 * Copyright (C) 2004 Andrew Khan, Eric Jung
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.biff;
21
22 import common.Logger;
23
24 /**
25 * Class which represents an Excel header or footer. Information for this
26 * class came from Microsoft Knowledge Base Article 142136
27 * (previously Q142136).
28 *
29 * This class encapsulates three internal structures representing the header
30 * or footer contents which appear on the left, right or central part of the
31 * page
32 */
33 public abstract class HeaderFooter
34 {
35 /**
36 * The logger
37 */
38 private static Logger logger = Logger.getLogger(HeaderFooter.class);
39
40 // Codes to format text
41
42 /**
43 * Turns bold printing on or off
44 */
45 private static final String BOLD_TOGGLE = "&B";
46
47 /**
48 * Turns underline printing on or off
49 */
50 private static final String UNDERLINE_TOGGLE = "&U";
51
52 /**
53 * Turns italic printing on or off
54 */
55 private static final String ITALICS_TOGGLE = "&I";
56
57 /**
58 * Turns strikethrough printing on or off
59 */
60 private static final String STRIKETHROUGH_TOGGLE = "&S";
61
62 /**
63 * Turns double-underline printing on or off
64 */
65 private static final String DOUBLE_UNDERLINE_TOGGLE = "&E";
66
67 /**
68 * Turns superscript printing on or off
69 */
70 private static final String SUPERSCRIPT_TOGGLE = "&X";
71
72 /**
73 * Turns subscript printing on or off
74 */
75 private static final String SUBSCRIPT_TOGGLE = "&Y";
76
77 /**
78 * Turns outline printing on or off (Macintosh only)
79 */
80 private static final String OUTLINE_TOGGLE = "&O";
81
82 /**
83 * Turns shadow printing on or off (Macintosh only)
84 */
85 private static final String SHADOW_TOGGLE = "&H";
86
87 /**
88 * Left-aligns the characters that follow
89 */
90 private static final String LEFT_ALIGN = "&L";
91
92 /**
93 * Centres the characters that follow
94 */
95 private static final String CENTRE = "&C";
96
97 /**
98 * Right-aligns the characters that follow
99 */
100 private static final String RIGHT_ALIGN = "&R";
101
102 // Codes to insert specific data
103
104 /**
105 * Prints the page number
106 */
107 private static final String PAGENUM = "&P";
108
109 /**
110 * Prints the total number of pages in the document
111 */
112 private static final String TOTAL_PAGENUM = "&N";
113
114 /**
115 * Prints the current date
116 */
117 private static final String DATE = "&D";
118
119 /**
120 * Prints the current time
121 */
122 private static final String TIME = "&T";
123
124 /**
125 * Prints the name of the workbook
126 */
127 private static final String WORKBOOK_NAME = "&F";
128
129 /**
130 * Prints the name of the worksheet
131 */
132 private static final String WORKSHEET_NAME = "&A";
133
134 /**
135 * The contents - a simple wrapper around a string buffer
136 */
137 protected static class Contents
138 {
139 /**
140 * The buffer containing the header/footer string
141 */
142 private StringBuffer contents;
143
144 /**
145 * The constructor
146 */
147 protected Contents()
148 {
149 contents = new StringBuffer();
150 }
151
152 /**
153 * Constructor used when reading worksheets. The string contains all
154 * the formatting (but not alignment characters
155 *
156 * @param s the format string
157 */
158 protected Contents(String s)
159 {
160 contents = new StringBuffer(s);
161 }
162
163 /**
164 * Copy constructor
165 *
166 * @param copy the contents to copy
167 */
168 protected Contents(Contents copy)
169 {
170 contents = new StringBuffer(copy.getContents());
171 }
172
173 /**
174 * Retrieves a <code>String</code>ified
175 * version of this object
176 *
177 * @return the header string
178 */
179 protected String getContents()
180 {
181 return contents != null ? contents.toString() : "";
182 }
183
184 /**
185 * Internal method which appends the text to the string buffer
186 *
187 * @param txt
188 */
189 private void appendInternal(String txt)
190 {
191 if (contents == null)
192 {
193 contents = new StringBuffer();
194 }
195
196 contents.append(txt);
197 }
198
199 /**
200 * Internal method which appends the text to the string buffer
201 *
202 * @param ch
203 */
204 private void appendInternal(char ch)
205 {
206 if (contents == null)
207 {
208 contents = new StringBuffer();
209 }
210
211 contents.append(ch);
212 }
213
214 /**
215 * Appends the text to the string buffer
216 *
217 * @param txt
218 */
219 protected void append(String txt)
220 {
221 appendInternal(txt);
222 }
223
224 /**
225 * Turns bold printing on or off. Bold printing
226 * is initially off. Text subsequently appended to
227 * this object will be bolded until this method is
228 * called again.
229 */
230 protected void toggleBold()
231 {
232 appendInternal(BOLD_TOGGLE);
233 }
234
235 /**
236 * Turns underline printing on or off. Underline printing
237 * is initially off. Text subsequently appended to
238 * this object will be underlined until this method is
239 * called again.
240 */
241 protected void toggleUnderline()
242 {
243 appendInternal(UNDERLINE_TOGGLE);
244 }
245
246 /**
247 * Turns italics printing on or off. Italics printing
248 * is initially off. Text subsequently appended to
249 * this object will be italicized until this method is
250 * called again.
251 */
252 protected void toggleItalics()
253 {
254 appendInternal(ITALICS_TOGGLE);
255 }
256
257 /**
258 * Turns strikethrough printing on or off. Strikethrough printing
259 * is initially off. Text subsequently appended to
260 * this object will be striked out until this method is
261 * called again.
262 */
263 protected void toggleStrikethrough()
264 {
265 appendInternal(STRIKETHROUGH_TOGGLE);
266 }
267
268 /**
269 * Turns double-underline printing on or off. Double-underline printing
270 * is initially off. Text subsequently appended to
271 * this object will be double-underlined until this method is
272 * called again.
273 */
274 protected void toggleDoubleUnderline()
275 {
276 appendInternal(DOUBLE_UNDERLINE_TOGGLE);
277 }
278
279 /**
280 * Turns superscript printing on or off. Superscript printing
281 * is initially off. Text subsequently appended to
282 * this object will be superscripted until this method is
283 * called again.
284 */
285 protected void toggleSuperScript()
286 {
287 appendInternal(SUPERSCRIPT_TOGGLE);
288 }
289
290 /**
291 * Turns subscript printing on or off. Subscript printing
292 * is initially off. Text subsequently appended to
293 * this object will be subscripted until this method is
294 * called again.
295 */
296 protected void toggleSubScript()
297 {
298 appendInternal(SUBSCRIPT_TOGGLE);
299 }
300
301 /**
302 * Turns outline printing on or off (Macintosh only).
303 * Outline printing is initially off. Text subsequently appended
304 * to this object will be outlined until this method is
305 * called again.
306 */
307 protected void toggleOutline()
308 {
309 appendInternal(OUTLINE_TOGGLE);
310 }
311
312 /**
313 * Turns shadow printing on or off (Macintosh only).
314 * Shadow printing is initially off. Text subsequently appended
315 * to this object will be shadowed until this method is
316 * called again.
317 */
318 protected void toggleShadow()
319 {
320 appendInternal(SHADOW_TOGGLE);
321 }
322
323 /**
324 * Sets the font of text subsequently appended to this
325 * object.. Previously appended text is not affected.
326 * <p/>
327 * <strong>Note:</strong> no checking is performed to
328 * determine if fontName is a valid font.
329 *
330 * @param fontName name of the font to use
331 */
332 protected void setFontName(String fontName)
333 {
334 // Font name must be in quotations
335 appendInternal("&\"");
336 appendInternal(fontName);
337 appendInternal('\"');
338 }
339
340 /**
341 * Sets the font size of text subsequently appended to this
342 * object. Previously appended text is not affected.
343 * <p/>
344 * Valid point sizes are between 1 and 99 (inclusive). If
345 * size is outside this range, this method returns false
346 * and does not change font size. If size is within this
347 * range, the font size is changed and true is returned.
348 *
349 * @param size The size in points. Valid point sizes are
350 * between 1 and 99 (inclusive).
351 * @return true if the font size was changed, false if font
352 * size was not changed because 1 > size > 99.
353 */
354 protected boolean setFontSize(int size)
355 {
356 if (size < 1 || size > 99)
357 {
358 return false;
359 }
360
361 // A two digit number should be used -- even if the
362 // leading number is just a zero.
363 String fontSize;
364 if (size < 10)
365 {
366 // single-digit -- make two digit
367 fontSize = "0" + size;
368 }
369 else
370 {
371 fontSize = Integer.toString(size);
372 }
373
374 appendInternal('&');
375 appendInternal(fontSize);
376 return true;
377 }
378
379 /**
380 * Appends the page number
381 */
382 protected void appendPageNumber()
383 {
384 appendInternal(PAGENUM);
385 }
386
387 /**
388 * Appends the total number of pages
389 */
390 protected void appendTotalPages()
391 {
392 appendInternal(TOTAL_PAGENUM);
393 }
394
395 /**
396 * Appends the current date
397 */
398 protected void appendDate()
399 {
400 appendInternal(DATE);
401 }
402
403 /**
404 * Appends the current time
405 */
406 protected void appendTime()
407 {
408 appendInternal(TIME);
409 }
410
411 /**
412 * Appends the workbook name
413 */
414 protected void appendWorkbookName()
415 {
416 appendInternal(WORKBOOK_NAME);
417 }
418
419 /**
420 * Appends the worksheet name
421 */
422 protected void appendWorkSheetName()
423 {
424 appendInternal(WORKSHEET_NAME);
425 }
426
427 /**
428 * Clears the contents of this portion
429 */
430 protected void clear()
431 {
432 contents = null;
433 }
434
435 /**
436 * Queries if the contents are empty
437 *
438 * @return TRUE if the contents are empty, FALSE otherwise
439 */
440 protected boolean empty()
441 {
442 if (contents == null || contents.length() == 0)
443 {
444 return true;
445 }
446 else
447 {
448 return false;
449 }
450 }
451 }
452
453 /**
454 * The left aligned header/footer contents
455 */
456 private Contents left;
457
458 /**
459 * The right aligned header/footer contents
460 */
461 private Contents right;
462
463 /**
464 * The centrally aligned header/footer contents
465 */
466 private Contents centre;
467
468 /**
469 * Default constructor.
470 */
471 protected HeaderFooter()
472 {
473 left = createContents();
474 right = createContents();
475 centre = createContents();
476 }
477
478 /**
479 * Copy constructor
480 *
481 * @param c the item to copy
482 */
483 protected HeaderFooter(HeaderFooter hf)
484 {
485 left = createContents(hf.left);
486 right = createContents(hf.right);
487 centre = createContents(hf.centre);
488 }
489
490 /**
491 * Constructor used when reading workbooks to separate the left, right
492 * a central part of the strings into their constituent parts
493 */
494 protected HeaderFooter(String s)
495 {
496 if (s == null || s.length() == 0)
497 {
498 left = createContents();
499 right = createContents();
500 centre = createContents();
501 return;
502 }
503
504 int pos = 0;
505 int leftPos = s.indexOf(LEFT_ALIGN);
506 int rightPos = s.indexOf(RIGHT_ALIGN);
507 int centrePos = s.indexOf(CENTRE);
508
509 // Do the left position string
510 if (pos == leftPos)
511 {
512 if (centrePos != -1)
513 {
514 left = createContents(s.substring(pos + 2, centrePos));
515 pos = centrePos;
516 }
517 else if (rightPos != -1 )
518 {
519 left = createContents(s.substring(pos + 2, rightPos));
520 pos = rightPos;
521 }
522 else
523 {
524 left = createContents(s.substring(pos + 2));
525 pos = s.length();
526 }
527 }
528
529 // Do the centrally positioned part of the string. This is the default
530 // if no alignment string is specified
531 if (pos == centrePos ||
532 (leftPos == -1 && rightPos == -1 && centrePos == -1))
533 {
534 if (rightPos != -1)
535 {
536 centre = createContents(s.substring(pos + 2, rightPos));
537 pos = rightPos;
538 }
539 else
540 {
541 int cpos = (pos == centrePos) ? pos + 2 : pos;
542 centre = createContents(s.substring(cpos));
543 pos = s.length();
544 }
545 }
546
547 // Do the right positioned part of the string
548 if (pos == rightPos)
549 {
550 right = createContents(s.substring(pos + 2));
551 pos = s.length();
552 }
553
554 if (left == null)
555 {
556 left = createContents();
557 }
558
559 if (centre == null)
560 {
561 centre = createContents();
562 }
563
564 if (right == null)
565 {
566 right = createContents();
567 }
568 }
569
570 /**
571 * Retrieves a <code>String</code>ified
572 * version of this object
573 *
574 * @return the header string
575 */
576 public String toString()
577 {
578 StringBuffer hf = new StringBuffer();
579 if (!left.empty())
580 {
581 hf.append(LEFT_ALIGN);
582 hf.append(left.getContents());
583 }
584
585 if (!centre.empty())
586 {
587 hf.append(CENTRE);
588 hf.append(centre.getContents());
589 }
590
591 if (!right.empty())
592 {
593 hf.append(RIGHT_ALIGN);
594 hf.append(right.getContents());
595 }
596
597 return hf.toString();
598 }
599
600 /**
601 * Accessor for the contents which appear on the right hand side of the page
602 *
603 * @return the right aligned contents
604 */
605 protected Contents getRightText()
606 {
607 return right;
608 }
609
610 /**
611 * Accessor for the contents which in the centre of the page
612 *
613 * @return the centrally aligned contents
614 */
615 protected Contents getCentreText()
616 {
617 return centre;
618 }
619
620 /**
621 * Accessor for the contents which appear on the left hand side of the page
622 *
623 * @return the left aligned contents
624 */
625 protected Contents getLeftText()
626 {
627 return left;
628 }
629
630 /**
631 * Clears the contents of the header/footer
632 */
633 protected void clear()
634 {
635 left.clear();
636 right.clear();
637 centre.clear();
638 }
639
640 /**
641 * Creates internal class of the appropriate type
642 */
643 protected abstract Contents createContents();
644
645 /**
646 * Creates internal class of the appropriate type
647 */
648 protected abstract Contents createContents(String s);
649
650 /**
651 * Creates internal class of the appropriate type
652 */
653 protected abstract Contents createContents(Contents c);
654 }