View | Details | Raw Unified | Return to bug 51351
Collapse All | Expand All

(-)src/org/apache/poi/hwpf/extractor/NumberFormatter.java (+43 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
/**
4
 * Comment me
5
 *
6
 * @author Ryan Ackley
7
 */
8
public final class NumberFormatter {
9
10
    private static String[] C_LETTERS = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i",
11
            "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "x", "y", "z" };
12
13
    private static String[] C_ROMAN = new String[] { "i", "ii", "iii", "iv", "v", "vi", "vii",
14
            "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv", "xvi", "xvii", "xviii", "xix",
15
            "xx", "xxi", "xxii", "xxiii", "xxiv", "xxv", "xxvi", "xxvii", "xxviii", "xxix", "xxx",
16
            "xxxi", "xxxii", "xxxiii", "xxxiv", "xxxv", "xxxvi", "xxxvii", "xxxvii", "xxxviii",
17
            "xxxix", "xl", "xli", "xlii", "xliii", "xliv", "xlv", "xlvi", "xlvii", "xlviii",
18
            "xlix", "l" };
19
20
    private final static int T_ARABIC = 0;
21
    private final static int T_LOWER_LETTER = 4;
22
    private final static int T_LOWER_ROMAN = 2;
23
    private final static int T_ORDINAL = 5;
24
    private final static int T_UPPER_LETTER = 3;
25
    private final static int T_UPPER_ROMAN = 1;
26
27
    public static String getNumber(int num, int style) {
28
        switch (style) {
29
        case T_UPPER_ROMAN:
30
            return C_ROMAN[num - 1].toUpperCase();
31
        case T_LOWER_ROMAN:
32
            return C_ROMAN[num - 1];
33
        case T_UPPER_LETTER:
34
            return C_LETTERS[num - 1].toUpperCase();
35
        case T_LOWER_LETTER:
36
            return C_LETTERS[num - 1];
37
        case T_ARABIC:
38
        case T_ORDINAL:
39
        default:
40
            return String.valueOf(num);
41
        }
42
    }
43
}
(-)src/org/apache/poi/hwpf/extractor/WordToFoUtils.java (+443 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
import java.lang.reflect.Constructor;
4
import java.lang.reflect.Field;
5
6
import org.apache.poi.hwpf.model.ListLevel;
7
import org.apache.poi.hwpf.model.ListTables;
8
import org.apache.poi.hwpf.usermodel.BorderCode;
9
import org.apache.poi.hwpf.usermodel.CharacterProperties;
10
import org.apache.poi.hwpf.usermodel.CharacterRun;
11
import org.apache.poi.hwpf.usermodel.Paragraph;
12
import org.apache.poi.hwpf.usermodel.Range;
13
import org.apache.poi.hwpf.usermodel.Section;
14
import org.apache.poi.hwpf.usermodel.SectionProperties;
15
import org.apache.poi.hwpf.usermodel.TableCell;
16
import org.apache.poi.hwpf.usermodel.TableIterator;
17
import org.apache.poi.hwpf.usermodel.TableRow;
18
import org.w3c.dom.Element;
19
20
public class WordToFoUtils {
21
    static final String EMPTY = "";
22
23
    public static final float TWIPS_PER_INCH = 1440.0f;
24
25
    public static final int TWIPS_PER_PT = 20;
26
27
    static boolean equals(String str1, String str2) {
28
	return str1 == null ? str2 == null : str1.equals(str2);
29
    }
30
31
    public static String getBorderType(BorderCode borderCode) {
32
	if (borderCode == null)
33
	    throw new IllegalArgumentException("borderCode is null");
34
35
	switch (borderCode.getBorderType()) {
36
	case 1:
37
	case 2:
38
	    return "solid";
39
	case 3:
40
	    return "double";
41
	case 5:
42
	    return "solid";
43
	case 6:
44
	    return "dotted";
45
	case 7:
46
	case 8:
47
	    return "dashed";
48
	case 9:
49
	    return "dotted";
50
	case 10:
51
	case 11:
52
	case 12:
53
	case 13:
54
	case 14:
55
	case 15:
56
	case 16:
57
	case 17:
58
	case 18:
59
	case 19:
60
	    return "double";
61
	case 20:
62
	    return "solid";
63
	case 21:
64
	    return "double";
65
	case 22:
66
	    return "dashed";
67
	case 23:
68
	    return "dashed";
69
	case 24:
70
	    return "ridge";
71
	case 25:
72
	    return "grooved";
73
	default:
74
	    return "solid";
75
	}
76
    }
77
78
    public static String getBorderWidth(BorderCode borderCode) {
79
	int lineWidth = borderCode.getLineWidth();
80
	int pt = lineWidth / 8;
81
	int pte = lineWidth - pt * 8;
82
83
	StringBuilder stringBuilder = new StringBuilder();
84
	stringBuilder.append(pt);
85
	stringBuilder.append(".");
86
	stringBuilder.append(1000 / 8 * pte);
87
	stringBuilder.append("pt");
88
	return stringBuilder.toString();
89
    }
90
91
    public static String getBulletText(ListTables listTables,
92
	    Paragraph paragraph, int listId) {
93
	final ListLevel listLevel = listTables.getLevel(listId,
94
		paragraph.getIlvl());
95
96
	if (listLevel.getNumberText() == null)
97
	    return EMPTY;
98
99
	StringBuffer bulletBuffer = new StringBuffer();
100
	char[] xst = listLevel.getNumberText().toCharArray();
101
	for (char element : xst) {
102
	    if (element < 9) {
103
		ListLevel numLevel = listTables.getLevel(listId, element);
104
105
		int num = numLevel.getStartAt();
106
		bulletBuffer.append(NumberFormatter.getNumber(num,
107
			listLevel.getNumberFormat()));
108
109
		if (numLevel == listLevel) {
110
		    numLevel.setStartAt(numLevel.getStartAt() + 1);
111
		}
112
113
	    } else {
114
		bulletBuffer.append(element);
115
	    }
116
	}
117
118
	byte follow = getIxchFollow(listLevel);
119
	switch (follow) {
120
	case 0:
121
	    bulletBuffer.append("\t");
122
	    break;
123
	case 1:
124
	    bulletBuffer.append(" ");
125
	    break;
126
	default:
127
	    break;
128
	}
129
130
	return bulletBuffer.toString();
131
    }
132
133
    public static String getColor(int ico) {
134
	switch (ico) {
135
	case 1:
136
	    return "black";
137
	case 2:
138
	    return "blue";
139
	case 3:
140
	    return "cyan";
141
	case 4:
142
	    return "green";
143
	case 5:
144
	    return "magenta";
145
	case 6:
146
	    return "red";
147
	case 7:
148
	    return "yellow";
149
	case 8:
150
	    return "white";
151
	case 9:
152
	    return "darkblue";
153
	case 10:
154
	    return "darkcyan";
155
	case 11:
156
	    return "darkgreen";
157
	case 12:
158
	    return "darkmagenta";
159
	case 13:
160
	    return "darkred";
161
	case 14:
162
	    return "darkyellow";
163
	case 15:
164
	    return "darkgray";
165
	case 16:
166
	    return "lightgray";
167
	default:
168
	    return "black";
169
	}
170
    }
171
172
    public static byte getIxchFollow(ListLevel listLevel) {
173
	try {
174
	    Field field = ListLevel.class.getDeclaredField("_ixchFollow");
175
	    field.setAccessible(true);
176
	    return ((Byte) field.get(listLevel)).byteValue();
177
	} catch (Exception exc) {
178
	    throw new Error(exc);
179
	}
180
    }
181
182
    public static String getListItemNumberLabel(int number, int format) {
183
184
	if (format != 0)
185
	    System.err.println("NYI: toListItemNumberLabel(): " + format);
186
187
	return String.valueOf(number);
188
    }
189
190
    public static SectionProperties getSectionProperties(Section section) {
191
	try {
192
	    Field field = Section.class.getDeclaredField("_props");
193
	    field.setAccessible(true);
194
	    return (SectionProperties) field.get(section);
195
	} catch (Exception exc) {
196
	    throw new Error(exc);
197
	}
198
    }
199
200
    static boolean isEmpty(String str) {
201
	return str == null || str.length() == 0;
202
    }
203
204
    static boolean isNotEmpty(String str) {
205
	return !isEmpty(str);
206
    }
207
208
    public static TableIterator newTableIterator(Range range, int level) {
209
	try {
210
	    Constructor<TableIterator> constructor = TableIterator.class
211
		    .getDeclaredConstructor(Range.class, int.class);
212
	    constructor.setAccessible(true);
213
	    return constructor.newInstance(range, Integer.valueOf(level));
214
	} catch (Exception exc) {
215
	    throw new Error(exc);
216
	}
217
    }
218
219
    public static void setBold(final Element element, final boolean bold) {
220
	element.setAttribute("font-weight", bold ? "bold" : "normal");
221
    }
222
223
    public static void setBorder(Element element, BorderCode borderCode,
224
	    String where) {
225
	if (element == null)
226
	    throw new IllegalArgumentException("element is null");
227
228
	if (borderCode == null)
229
	    return;
230
231
	if (isEmpty(where)) {
232
	    element.setAttribute("border-style", getBorderType(borderCode));
233
	    element.setAttribute("border-color",
234
		    getColor(borderCode.getColor()));
235
	    element.setAttribute("border-width", getBorderWidth(borderCode));
236
	} else {
237
	    element.setAttribute("border-" + where + "-style",
238
		    getBorderType(borderCode));
239
	    element.setAttribute("border-" + where + "-color",
240
		    getColor(borderCode.getColor()));
241
	    element.setAttribute("border-" + where + "-width",
242
		    getBorderWidth(borderCode));
243
	}
244
    }
245
246
    public static void setCharactersProperties(final CharacterRun characterRun,
247
	    final Element inline) {
248
	final CharacterProperties clonedProperties = characterRun
249
		.cloneProperties();
250
	StringBuilder textDecorations = new StringBuilder();
251
252
	setBorder(inline, clonedProperties.getBrc(), EMPTY);
253
254
	if (characterRun.isCapitalized()) {
255
	    inline.setAttribute("text-transform", "uppercase");
256
	}
257
	if (characterRun.isHighlighted()) {
258
	    inline.setAttribute("background-color",
259
		    getColor(clonedProperties.getIcoHighlight()));
260
	}
261
	if (characterRun.isStrikeThrough()) {
262
	    if (textDecorations.length() > 0)
263
		textDecorations.append(" ");
264
	    textDecorations.append("line-through");
265
	}
266
	if (characterRun.isShadowed()) {
267
	    inline.setAttribute("text-shadow", characterRun.getFontSize() / 24
268
		    + "pt");
269
	}
270
	if (characterRun.isSmallCaps()) {
271
	    inline.setAttribute("font-variant", "small-caps");
272
	}
273
	if (characterRun.getSubSuperScriptIndex() == 1) {
274
	    inline.setAttribute("baseline-shift", "super");
275
	    inline.setAttribute("font-size", "smaller");
276
	}
277
	if (characterRun.getSubSuperScriptIndex() == 2) {
278
	    inline.setAttribute("baseline-shift", "sub");
279
	    inline.setAttribute("font-size", "smaller");
280
	}
281
	if (characterRun.getUnderlineCode() > 0) {
282
	    if (textDecorations.length() > 0)
283
		textDecorations.append(" ");
284
	    textDecorations.append("underline");
285
	}
286
	if (textDecorations.length() > 0) {
287
	    inline.setAttribute("text-decoration", textDecorations.toString());
288
	}
289
    }
290
291
    public static void setFontFamily(final Element element,
292
	    final String fontFamily) {
293
	element.setAttribute("font-family", fontFamily);
294
    }
295
296
    public static void setFontSize(final Element element, final int fontSize) {
297
	element.setAttribute("font-size", String.valueOf(fontSize));
298
    }
299
300
    public static void setIndent(Paragraph paragraph, Element block) {
301
	if (paragraph.getFirstLineIndent() != 0) {
302
	    block.setAttribute(
303
		    "text-indent",
304
		    String.valueOf(paragraph.getFirstLineIndent()
305
			    / TWIPS_PER_PT)
306
			    + "pt");
307
	}
308
	if (paragraph.getIndentFromLeft() != 0) {
309
	    block.setAttribute(
310
		    "start-indent",
311
		    String.valueOf(paragraph.getIndentFromLeft() / TWIPS_PER_PT)
312
			    + "pt");
313
	}
314
	if (paragraph.getIndentFromRight() != 0) {
315
	    block.setAttribute(
316
		    "end-indent",
317
		    String.valueOf(paragraph.getIndentFromRight()
318
			    / TWIPS_PER_PT)
319
			    + "pt");
320
	}
321
	if (paragraph.getSpacingBefore() != 0) {
322
	    block.setAttribute("space-before",
323
		    String.valueOf(paragraph.getSpacingBefore() / TWIPS_PER_PT)
324
			    + "pt");
325
	}
326
	if (paragraph.getSpacingAfter() != 0) {
327
	    block.setAttribute("space-after",
328
		    String.valueOf(paragraph.getSpacingAfter() / TWIPS_PER_PT)
329
			    + "pt");
330
	}
331
    }
332
333
    public static void setItalic(final Element element, final boolean italic) {
334
	element.setAttribute("font-style", italic ? "italic" : "normal");
335
    }
336
337
    public static void setJustification(Paragraph paragraph,
338
	    final Element element) {
339
	final int justification = paragraph.getJustification();
340
	switch (justification) {
341
	case 0:
342
	    element.setAttribute("text-align", "start");
343
	    break;
344
	case 1:
345
	    element.setAttribute("text-align", "center");
346
	    break;
347
	case 2:
348
	    element.setAttribute("text-align", "end");
349
	    break;
350
	case 3:
351
	    element.setAttribute("text-align", "justify");
352
	    break;
353
	case 4:
354
	    element.setAttribute("text-align", "justify");
355
	    break;
356
	case 5:
357
	    element.setAttribute("text-align", "center");
358
	    break;
359
	case 6:
360
	    element.setAttribute("text-align", "left");
361
	    break;
362
	case 7:
363
	    element.setAttribute("text-align", "start");
364
	    break;
365
	case 8:
366
	    element.setAttribute("text-align", "end");
367
	    break;
368
	case 9:
369
	    element.setAttribute("text-align", "justify");
370
	    break;
371
	}
372
    }
373
374
    public static void setParagraphProperties(Paragraph paragraph, Element block) {
375
	setIndent(paragraph, block);
376
	setJustification(paragraph, block);
377
378
	setBorder(block, paragraph.getBottomBorder(), "bottom");
379
	setBorder(block, paragraph.getLeftBorder(), "left");
380
	setBorder(block, paragraph.getRightBorder(), "right");
381
	setBorder(block, paragraph.getTopBorder(), "top");
382
383
	if (paragraph.pageBreakBefore()) {
384
	    block.setAttribute("break-before", "page");
385
	}
386
387
	block.setAttribute("hyphenate",
388
		String.valueOf(paragraph.isAutoHyphenated()));
389
390
	if (paragraph.keepOnPage()) {
391
	    block.setAttribute("keep-together.within-page", "always");
392
	}
393
394
	if (paragraph.keepWithNext()) {
395
	    block.setAttribute("keep-with-next.within-page", "always");
396
	}
397
398
	block.setAttribute("linefeed-treatment", "preserve");
399
	block.setAttribute("white-space-collapse", "false");
400
    }
401
402
    public static void setTableCellProperties(TableRow tableRow,
403
	    TableCell tableCell, Element element, boolean toppest,
404
	    boolean bottomest, boolean leftest, boolean rightest) {
405
	element.setAttribute("width", (tableCell.getWidth() / TWIPS_PER_INCH)
406
		+ "in");
407
	element.setAttribute("padding-start",
408
		(tableRow.getGapHalf() / TWIPS_PER_INCH) + "in");
409
	element.setAttribute("padding-end",
410
		(tableRow.getGapHalf() / TWIPS_PER_INCH) + "in");
411
412
	BorderCode top = tableCell.getBrcTop() != null ? tableCell.getBrcTop()
413
		: toppest ? tableRow.getTopBorder() : tableRow
414
			.getHorizontalBorder();
415
	BorderCode bottom = tableCell.getBrcBottom() != null ? tableCell
416
		.getBrcBottom() : bottomest ? tableRow.getBottomBorder()
417
		: tableRow.getHorizontalBorder();
418
419
	BorderCode left = tableCell.getBrcLeft() != null ? tableCell
420
		.getBrcLeft() : leftest ? tableRow.getLeftBorder() : tableRow
421
		.getVerticalBorder();
422
	BorderCode right = tableCell.getBrcRight() != null ? tableCell
423
		.getBrcRight() : rightest ? tableRow.getRightBorder()
424
		: tableRow.getVerticalBorder();
425
426
	setBorder(element, bottom, "bottom");
427
	setBorder(element, left, "left");
428
	setBorder(element, right, "right");
429
	setBorder(element, top, "top");
430
    }
431
432
    public static void setTableRowProperties(TableRow tableRow,
433
	    Element tableRowElement) {
434
	if (tableRow.getRowHeight() > 0) {
435
	    tableRowElement.setAttribute("height",
436
		    (tableRow.getRowHeight() / TWIPS_PER_INCH) + "in");
437
	}
438
	if (!tableRow.cantSplit()) {
439
	    tableRowElement.setAttribute("keep-together", "always");
440
	}
441
    }
442
443
}
(-)src/org/apache/poi/hwpf/extractor/WordToFoExtractor.java (+581 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
import java.io.File;
4
import java.io.FileInputStream;
5
import java.io.IOException;
6
import java.util.HashMap;
7
import java.util.Map;
8
9
import javax.xml.parsers.DocumentBuilderFactory;
10
11
import org.apache.poi.hwpf.HWPFDocument;
12
import org.apache.poi.hwpf.model.ListFormatOverride;
13
import org.apache.poi.hwpf.model.ListTables;
14
import org.apache.poi.hwpf.usermodel.CharacterRun;
15
import org.apache.poi.hwpf.usermodel.Paragraph;
16
import org.apache.poi.hwpf.usermodel.Picture;
17
import org.apache.poi.hwpf.usermodel.Range;
18
import org.apache.poi.hwpf.usermodel.Section;
19
import org.apache.poi.hwpf.usermodel.SectionProperties;
20
import org.apache.poi.hwpf.usermodel.Table;
21
import org.apache.poi.hwpf.usermodel.TableCell;
22
import org.apache.poi.hwpf.usermodel.TableIterator;
23
import org.apache.poi.hwpf.usermodel.TableRow;
24
import org.w3c.dom.Document;
25
import org.w3c.dom.Element;
26
import org.w3c.dom.Text;
27
28
import static org.apache.poi.hwpf.extractor.WordToFoUtils.TWIPS_PER_INCH;
29
30
/**
31
 * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
32
 */
33
public class WordToFoExtractor {
34
35
    private static final byte BEL_MARK = 7;
36
37
    private static final byte FIELD_BEGIN_MARK = 19;
38
39
    private static final byte FIELD_END_MARK = 21;
40
41
    private static final byte FIELD_SEPARATOR_MARK = 20;
42
43
    private static final String NS_XSLFO = "http://www.w3.org/1999/XSL/Format";
44
45
    private static HWPFDocument loadDoc(File docFile) throws IOException {
46
	final FileInputStream istream = new FileInputStream(docFile);
47
	try {
48
	    return new HWPFDocument(istream);
49
	} finally {
50
	    try {
51
		istream.close();
52
	    } catch (Exception exc) {
53
		// no op
54
	    }
55
	}
56
    }
57
58
    static Document process(File docFile) throws Exception {
59
	final HWPFDocument hwpfDocument = loadDoc(docFile);
60
	WordToFoExtractor wordToFoExtractor = new WordToFoExtractor(
61
		DocumentBuilderFactory.newInstance().newDocumentBuilder()
62
			.newDocument());
63
	wordToFoExtractor.processDocument(hwpfDocument);
64
	return wordToFoExtractor.getDocument();
65
    }
66
67
    private final Document document;
68
69
    private final Element layoutMasterSet;
70
71
    private final Element root;
72
73
    public WordToFoExtractor(Document document) throws Exception {
74
	this.document = document;
75
76
	root = document.createElementNS(NS_XSLFO, "fo:root");
77
	document.appendChild(root);
78
79
	layoutMasterSet = document.createElementNS(NS_XSLFO,
80
		"fo:layout-master-set");
81
	root.appendChild(layoutMasterSet);
82
    }
83
84
    protected Element addFlowToPageSequence(final Element pageSequence,
85
	    String flowName) {
86
	final Element flow = document.createElementNS(NS_XSLFO, "fo:flow");
87
	flow.setAttribute("flow-name", flowName);
88
	pageSequence.appendChild(flow);
89
90
	return flow;
91
    }
92
93
    protected Element addListItem(Element listBlock) {
94
	Element result = createListItem();
95
	listBlock.appendChild(result);
96
	return result;
97
    }
98
99
    protected Element addListItemBody(Element listItem) {
100
	Element result = createListItemBody();
101
	listItem.appendChild(result);
102
	return result;
103
    }
104
105
    protected Element addListItemLabel(Element listItem, String text) {
106
	Element result = createListItemLabel(text);
107
	listItem.appendChild(result);
108
	return result;
109
    }
110
111
    protected Element addPageSequence(String pageMaster) {
112
	final Element pageSequence = document.createElementNS(NS_XSLFO,
113
		"fo:page-sequence");
114
	pageSequence.setAttribute("master-reference", pageMaster);
115
	root.appendChild(pageSequence);
116
	return pageSequence;
117
    }
118
119
    protected Element addRegionBody(Element pageMaster) {
120
	final Element regionBody = document.createElementNS(NS_XSLFO,
121
		"fo:region-body");
122
	pageMaster.appendChild(regionBody);
123
124
	return regionBody;
125
    }
126
127
    protected Element addSimplePageMaster(String masterName) {
128
	final Element simplePageMaster = document.createElementNS(NS_XSLFO,
129
		"fo:simple-page-master");
130
	simplePageMaster.setAttribute("master-name", masterName);
131
	layoutMasterSet.appendChild(simplePageMaster);
132
133
	return simplePageMaster;
134
    }
135
136
    protected Element addTable(Element flow) {
137
	final Element table = document.createElementNS(NS_XSLFO, "fo:table");
138
	flow.appendChild(table);
139
	return table;
140
    }
141
142
    protected Element createBlock() {
143
	return document.createElementNS(NS_XSLFO, "fo:block");
144
    }
145
146
    protected Element createExternalGraphic(String source) {
147
	Element result = document.createElementNS(NS_XSLFO,
148
		"fo:external-graphic");
149
	result.setAttribute("src", "url('" + source + "')");
150
	return result;
151
    }
152
153
    protected Element createInline() {
154
	return document.createElementNS(NS_XSLFO, "fo:inline");
155
    }
156
157
    protected Element createLeader() {
158
	return document.createElementNS(NS_XSLFO, "fo:leader");
159
    }
160
161
    protected Element createListBlock() {
162
	return document.createElementNS(NS_XSLFO, "fo:list-block");
163
    }
164
165
    protected Element createListItem() {
166
	return document.createElementNS(NS_XSLFO, "fo:list-item");
167
    }
168
169
    protected Element createListItemBody() {
170
	return document.createElementNS(NS_XSLFO, "fo:list-item-body");
171
    }
172
173
    protected Element createListItemLabel(String text) {
174
	Element result = document.createElementNS(NS_XSLFO,
175
		"fo:list-item-label");
176
	Element block = createBlock();
177
	block.appendChild(document.createTextNode(text));
178
	result.appendChild(block);
179
	return result;
180
    }
181
182
    protected String createPageMaster(SectionProperties sep, String type,
183
	    int section) {
184
	float height = sep.getYaPage() / TWIPS_PER_INCH;
185
	float width = sep.getXaPage() / TWIPS_PER_INCH;
186
	float leftMargin = sep.getDxaLeft() / TWIPS_PER_INCH;
187
	float rightMargin = sep.getDxaRight() / TWIPS_PER_INCH;
188
	float topMargin = sep.getDyaTop() / TWIPS_PER_INCH;
189
	float bottomMargin = sep.getDyaBottom() / TWIPS_PER_INCH;
190
191
	// add these to the header
192
	String pageMasterName = type + "-page" + section;
193
194
	Element pageMaster = addSimplePageMaster(pageMasterName);
195
	pageMaster.setAttribute("page-height", height + "in");
196
	pageMaster.setAttribute("page-width", width + "in");
197
198
	Element regionBody = addRegionBody(pageMaster);
199
	regionBody.setAttribute("margin", topMargin + "in " + rightMargin
200
		+ "in " + bottomMargin + "in " + leftMargin + "in");
201
202
	/*
203
	 * 6.4.14 fo:region-body
204
	 *
205
	 * The values of the padding and border-width traits must be "0".
206
	 */
207
	// WordToFoUtils.setBorder(regionBody, sep.getBrcTop(), "top");
208
	// WordToFoUtils.setBorder(regionBody, sep.getBrcBottom(), "bottom");
209
	// WordToFoUtils.setBorder(regionBody, sep.getBrcLeft(), "left");
210
	// WordToFoUtils.setBorder(regionBody, sep.getBrcRight(), "right");
211
212
	if (sep.getCcolM1() > 0) {
213
	    regionBody.setAttribute("column-count", "" + (sep.getCcolM1() + 1));
214
	    if (sep.getFEvenlySpaced()) {
215
		regionBody.setAttribute("column-gap",
216
			(sep.getDxaColumns() / TWIPS_PER_INCH) + "in");
217
	    } else {
218
		regionBody.setAttribute("column-gap", "0.25in");
219
	    }
220
	}
221
222
	return pageMasterName;
223
    }
224
225
    protected Element createTableBody() {
226
	return document.createElementNS(NS_XSLFO, "fo:table-body");
227
    }
228
229
    protected Element createTableCell() {
230
	return document.createElementNS(NS_XSLFO, "fo:table-cell");
231
    }
232
233
    protected Element createTableHeader() {
234
	return document.createElementNS(NS_XSLFO, "fo:table-header");
235
    }
236
237
    protected Element createTableRow() {
238
	return document.createElementNS(NS_XSLFO, "fo:table-row");
239
    }
240
241
    protected Text createText(String data) {
242
	return document.createTextNode(data);
243
    }
244
245
    public Document getDocument() {
246
	return document;
247
    }
248
249
    public void processDocument(HWPFDocument hwpfDocument) {
250
	final Range range = hwpfDocument.getRange();
251
252
	for (int s = 0; s < range.numSections(); s++) {
253
	    processSection(hwpfDocument, range.getSection(s), s);
254
	}
255
    }
256
257
    @SuppressWarnings("unused")
258
    protected void processImage(Element currentBlock, Picture picture) {
259
	// no default implementation -- skip
260
    }
261
262
    protected void processParagraph(HWPFDocument hwpfDocument,
263
	    Element parentFopElement, int currentTableLevel,
264
	    Paragraph paragraph, String bulletText) {
265
	final Element block = createBlock();
266
	parentFopElement.appendChild(block);
267
268
	WordToFoUtils.setParagraphProperties(paragraph, block);
269
270
	final int charRuns = paragraph.numCharacterRuns();
271
272
	if (charRuns == 0) {
273
	    return;
274
	}
275
276
	final String pFontName;
277
	final int pFontSize;
278
	final boolean pBold;
279
	final boolean pItalic;
280
	{
281
	    CharacterRun characterRun = paragraph.getCharacterRun(0);
282
	    pFontSize = characterRun.getFontSize() / 2;
283
	    pFontName = characterRun.getFontName();
284
	    pBold = characterRun.isBold();
285
	    pItalic = characterRun.isItalic();
286
	}
287
	WordToFoUtils.setFontFamily(block, pFontName);
288
	WordToFoUtils.setFontSize(block, pFontSize);
289
	WordToFoUtils.setBold(block, pBold);
290
	WordToFoUtils.setItalic(block, pItalic);
291
292
	StringBuilder lineText = new StringBuilder();
293
294
	if (WordToFoUtils.isNotEmpty(bulletText)) {
295
	    Element inline = createInline();
296
	    block.appendChild(inline);
297
298
	    Text textNode = createText(bulletText);
299
	    inline.appendChild(textNode);
300
301
	    lineText.append(bulletText);
302
	}
303
304
	for (int c = 0; c < charRuns; c++) {
305
	    CharacterRun characterRun = paragraph.getCharacterRun(c);
306
307
	    String text = characterRun.text();
308
	    if (text.getBytes().length == 0)
309
		continue;
310
311
	    if (text.getBytes()[0] == FIELD_BEGIN_MARK) {
312
		int skipTo = tryImageWithinField(hwpfDocument, paragraph, c,
313
			block);
314
315
		if (skipTo != c) {
316
		    c = skipTo;
317
		    continue;
318
		}
319
		continue;
320
	    }
321
	    if (text.getBytes()[0] == FIELD_SEPARATOR_MARK) {
322
		continue;
323
	    }
324
	    if (text.getBytes()[0] == FIELD_END_MARK) {
325
		continue;
326
	    }
327
328
	    if (characterRun.isSpecialCharacter() || characterRun.isObj()
329
		    || characterRun.isOle2()) {
330
		continue;
331
	    }
332
333
	    Element inline = createInline();
334
	    if (characterRun.isBold() != pBold) {
335
		WordToFoUtils.setBold(inline, characterRun.isBold());
336
	    }
337
	    if (characterRun.isItalic() != pItalic) {
338
		WordToFoUtils.setItalic(inline, characterRun.isItalic());
339
	    }
340
	    if (!WordToFoUtils.equals(characterRun.getFontName(), pFontName)) {
341
		WordToFoUtils.setFontFamily(inline, characterRun.getFontName());
342
	    }
343
	    if (characterRun.getFontSize() / 2 != pFontSize) {
344
		WordToFoUtils.setFontSize(inline,
345
			characterRun.getFontSize() / 2);
346
	    }
347
	    WordToFoUtils.setCharactersProperties(characterRun, inline);
348
	    block.appendChild(inline);
349
350
	    if (text.endsWith("\r")
351
		    || (text.charAt(text.length() - 1) == BEL_MARK && currentTableLevel != 0))
352
		text = text.substring(0, text.length() - 1);
353
354
	    Text textNode = createText(text);
355
	    inline.appendChild(textNode);
356
357
	    lineText.append(text);
358
	}
359
360
	if (lineText.toString().trim().length() == 0) {
361
	    Element leader = createLeader();
362
	    block.appendChild(leader);
363
	}
364
365
	return;
366
    }
367
368
    protected void processSection(HWPFDocument hwpfDocument, Section section,
369
	    int sectionCounter) {
370
	String regularPage = createPageMaster(
371
		WordToFoUtils.getSectionProperties(section), "page",
372
		sectionCounter);
373
374
	Element pageSequence = addPageSequence(regularPage);
375
	Element flow = addFlowToPageSequence(pageSequence, "xsl-region-body");
376
377
	processSectionParagraphes(hwpfDocument, flow, section, 0);
378
    }
379
380
    protected void processSectionParagraphes(HWPFDocument hwpfDocument,
381
	    Element flow, Range range, int currentTableLevel) {
382
	final Map<Integer, Table> allTables = new HashMap<Integer, Table>();
383
	for (TableIterator tableIterator = WordToFoUtils.newTableIterator(
384
		range, currentTableLevel + 1); tableIterator.hasNext();) {
385
	    Table next = tableIterator.next();
386
	    allTables.put(Integer.valueOf(next.getStartOffset()), next);
387
	}
388
389
	final ListTables listTables = hwpfDocument.getListTables();
390
	int currentListInfo = 0;
391
392
	final int paragraphs = range.numParagraphs();
393
	for (int p = 0; p < paragraphs; p++) {
394
	    Paragraph paragraph = range.getParagraph(p);
395
396
	    if (allTables.containsKey(Integer.valueOf(paragraph
397
		    .getStartOffset()))) {
398
		Table table = allTables.get(Integer.valueOf(paragraph
399
			.getStartOffset()));
400
		processTable(hwpfDocument, flow, table, currentTableLevel + 1);
401
		continue;
402
	    }
403
404
	    if (paragraph.isInTable()
405
		    && paragraph.getTableLevel() != currentTableLevel) {
406
		continue;
407
	    }
408
409
	    if (paragraph.getIlfo() != currentListInfo) {
410
		currentListInfo = paragraph.getIlfo();
411
	    }
412
413
	    if (currentListInfo != 0) {
414
		final ListFormatOverride listFormatOverride = listTables
415
			.getOverride(paragraph.getIlfo());
416
417
		String label = WordToFoUtils.getBulletText(listTables,
418
			paragraph, listFormatOverride.getLsid());
419
420
		processParagraph(hwpfDocument, flow, currentTableLevel,
421
			paragraph, label);
422
	    } else {
423
		processParagraph(hwpfDocument, flow, currentTableLevel,
424
			paragraph, WordToFoUtils.EMPTY);
425
	    }
426
	}
427
428
    }
429
430
    protected void processTable(HWPFDocument hwpfDocument, Element flow,
431
	    Table table, int thisTableLevel) {
432
	Element tableElement = addTable(flow);
433
434
	Element tableHeader = createTableHeader();
435
	Element tableBody = createTableBody();
436
437
	final int tableRows = table.numRows();
438
439
	int maxColumns = Integer.MIN_VALUE;
440
	for (int r = 0; r < tableRows; r++) {
441
	    maxColumns = Math.max(maxColumns, table.getRow(r).numCells());
442
	}
443
444
	for (int r = 0; r < tableRows; r++) {
445
	    TableRow tableRow = table.getRow(r);
446
447
	    Element tableRowElement = createTableRow();
448
	    WordToFoUtils.setTableRowProperties(tableRow, tableRowElement);
449
450
	    final int rowCells = tableRow.numCells();
451
	    for (int c = 0; c < rowCells; c++) {
452
		TableCell tableCell = tableRow.getCell(c);
453
454
		if (tableCell.isMerged() && !tableCell.isFirstMerged())
455
		    continue;
456
457
		if (tableCell.isVerticallyMerged()
458
			&& !tableCell.isFirstVerticallyMerged())
459
		    continue;
460
461
		Element tableCellElement = createTableCell();
462
		WordToFoUtils.setTableCellProperties(tableRow, tableCell,
463
			tableCellElement, r == 0, r == tableRows - 1, c == 0,
464
			c == rowCells - 1);
465
466
		if (tableCell.isFirstMerged()) {
467
		    int count = 0;
468
		    for (int c1 = c; c1 < rowCells; c1++) {
469
			TableCell nextCell = tableRow.getCell(c1);
470
			if (nextCell.isMerged())
471
			    count++;
472
			if (!nextCell.isMerged())
473
			    break;
474
		    }
475
		    tableCellElement.setAttribute("number-columns-spanned", ""
476
			    + count);
477
		} else {
478
		    if (c == rowCells - 1 && c != maxColumns - 1) {
479
			tableCellElement.setAttribute("number-columns-spanned",
480
				"" + (maxColumns - c));
481
		    }
482
		}
483
484
		if (tableCell.isFirstVerticallyMerged()) {
485
		    int count = 0;
486
		    for (int r1 = r; r1 < tableRows; r1++) {
487
			TableRow nextRow = table.getRow(r1);
488
			if (nextRow.numCells() < c)
489
			    break;
490
			TableCell nextCell = nextRow.getCell(c);
491
			if (nextCell.isVerticallyMerged())
492
			    count++;
493
			if (!nextCell.isVerticallyMerged())
494
			    break;
495
		    }
496
		    tableCellElement.setAttribute("number-rows-spanned", ""
497
			    + count);
498
		}
499
500
		processSectionParagraphes(hwpfDocument, tableCellElement,
501
			tableCell, thisTableLevel);
502
503
		if (!tableCellElement.hasChildNodes()) {
504
		    tableCellElement.appendChild(createBlock());
505
		}
506
507
		tableRowElement.appendChild(tableCellElement);
508
	    }
509
510
	    if (tableRow.isTableHeader()) {
511
		tableHeader.appendChild(tableRowElement);
512
	    } else {
513
		tableBody.appendChild(tableRowElement);
514
	    }
515
	}
516
517
	if (tableHeader.hasChildNodes()) {
518
	    tableElement.appendChild(tableHeader);
519
	}
520
	if (tableBody.hasChildNodes()) {
521
	    tableElement.appendChild(tableBody);
522
	} else {
523
	    System.err.println("Table without body");
524
	}
525
    }
526
527
    protected int tryImageWithinField(HWPFDocument hwpfDocument,
528
	    Paragraph paragraph, int beginMark, Element currentBlock) {
529
	int separatorMark = -1;
530
	int pictureMark = -1;
531
	int endMark = -1;
532
	for (int c = beginMark + 1; c < paragraph.numCharacterRuns(); c++) {
533
	    CharacterRun characterRun = paragraph.getCharacterRun(c);
534
535
	    String text = characterRun.text();
536
	    if (text.getBytes().length == 0)
537
		continue;
538
539
	    if (text.getBytes()[0] == FIELD_SEPARATOR_MARK) {
540
		if (separatorMark != -1) {
541
		    // double;
542
		    return beginMark;
543
		}
544
545
		separatorMark = c;
546
		continue;
547
	    }
548
549
	    if (text.getBytes()[0] == FIELD_END_MARK) {
550
		if (endMark != -1) {
551
		    // double;
552
		    return beginMark;
553
		}
554
555
		endMark = c;
556
		break;
557
	    }
558
559
	    if (hwpfDocument.getPicturesTable().hasPicture(characterRun)) {
560
		if (pictureMark != -1) {
561
		    // double;
562
		    return beginMark;
563
		}
564
565
		pictureMark = c;
566
		continue;
567
	    }
568
	}
569
570
	if (separatorMark == -1 || pictureMark == -1 || endMark == -1)
571
	    return beginMark;
572
573
	final CharacterRun pictureRun = paragraph.getCharacterRun(pictureMark);
574
	final Picture picture = hwpfDocument.getPicturesTable().extractPicture(
575
		pictureRun, true);
576
	processImage(currentBlock, picture);
577
578
	return endMark;
579
    }
580
581
}

Return to bug 51351