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

(-)src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNumberedList2.java (+131 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.hslf.usermodel;
19
20
import java.util.List;
21
22
import junit.framework.TestCase;
23
24
import org.apache.poi.hslf.model.Slide;
25
import org.apache.poi.hslf.model.TextRun;
26
import org.apache.poi.hslf.model.textproperties.TextPFException9;
27
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
28
import org.apache.poi.hslf.record.EscherTextboxWrapper;
29
import org.apache.poi.hslf.record.StyleTextProp9Atom;
30
import org.apache.poi.hslf.record.StyleTextPropAtom;
31
import org.apache.poi.hslf.record.TextAutoNumberSchemeEnum;
32
import org.apache.poi.POIDataSamples;
33
34
35
/**
36
 * Test that checks numbered list functionality.
37
 * if a paragraph has autonumber ()
38
 * @see http://social.msdn.microsoft.com/Forums/mr-IN/os_binaryfile/thread/650888db-fabd-4b95-88dc-f0455f6e2d28
39
 * 
40
 * @author Alex Nikiforov [mailto:anikif@gmail.com]
41
 */
42
public final class TestNumberedList2 extends TestCase {
43
    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
44
45
	protected void setUp() throws Exception {
46
	}
47
48
	public void testNumberedList() throws Exception {
49
		SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("numbers2.ppt"));
50
		assertTrue("No Exceptions while reading file", true);
51
52
		final Slide[] slides = ppt.getSlides();
53
		assertEquals(2, slides.length);
54
		checkSlide0(slides[0]);
55
		checkSlide1(slides[1]);
56
		for (TextRun tr : slides[0].getTextRuns()) {
57
			System.out.println(tr.getRawText());
58
		}
59
		for (TextRun tr : slides[1].getTextRuns()) {
60
			System.out.println(tr.getRawText());
61
		}
62
	}
63
	private void checkSlide0(final Slide s) {
64
		final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();
65
		assertNotNull(numberedListArray);
66
		assertEquals(2, numberedListArray.length);
67
		final StyleTextProp9Atom numberedListInfoForTextBox0 = numberedListArray[0];
68
		final StyleTextProp9Atom numberedListInfoForTextBox1 = numberedListArray[1];
69
		assertNotNull(numberedListInfoForTextBox0);
70
		assertNotNull(numberedListInfoForTextBox1);
71
		final TextPFException9[] autoNumbersOfTextBox0 = numberedListInfoForTextBox0.getAutoNumberTypes();
72
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox0[0].getfBulletHasAutoNumber());
73
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox0[0].getAutoNumberStartNumber());//Default value = 1 will be used 
74
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox0[0].getAutoNumberScheme());
75
		final TextPFException9[] autoNumbersOfTextBox1 = numberedListInfoForTextBox1.getAutoNumberTypes();
76
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox1[0].getfBulletHasAutoNumber());
77
		assertEquals(Short.valueOf((short)6), autoNumbersOfTextBox1[0].getAutoNumberStartNumber());//Default value = 1 will be used 
78
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox1[0].getAutoNumberScheme());
79
80
		
81
		TextRun[] textRuns = s.getTextRuns();
82
		assertEquals(2, textRuns.length);
83
84
		RichTextRun textRun = textRuns[0].getRichTextRuns()[0];
85
		assertEquals("List Item One\rList Item Two\rList Item Three", textRun.getRawText());
86
		assertEquals(1, textRuns[0].getRichTextRuns().length);
87
		assertTrue(textRun.isBullet());
88
89
		assertEquals("A numbered list may start at any number \rThis would be used as a continuation list on another page\rThis list should start with #6", textRuns[1].getRawText());
90
		
91
		final EscherTextboxWrapper[] styleAtoms = s.getTextboxWrappers();
92
		assertEquals(textRuns.length, styleAtoms.length);
93
		checkSingleRunWrapper(44, styleAtoms[0]);
94
		checkSingleRunWrapper(130, styleAtoms[1]);
95
	}
96
	private void checkSlide1(final Slide s) {
97
		final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();
98
		assertNotNull(numberedListArray);
99
		assertEquals(1, numberedListArray.length);
100
		final StyleTextProp9Atom numberedListInfoForTextBox = numberedListArray[0];
101
		assertNotNull(numberedListInfoForTextBox);
102
		final TextPFException9[] autoNumbersOfTextBox = numberedListInfoForTextBox.getAutoNumberTypes();
103
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox[0].getfBulletHasAutoNumber());
104
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox[0].getAutoNumberStartNumber());//Default value = 1 will be used 
105
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox[0].getAutoNumberScheme());
106
			
107
		TextRun[] textRuns = s.getTextRuns();
108
		assertEquals(3, textRuns.length);
109
110
		RichTextRun textRun = textRuns[0].getRichTextRuns()[0];
111
		assertEquals("Bulleted list\rMore bullets", textRun.getRawText());
112
		assertEquals(1, textRuns[0].getRichTextRuns().length);
113
		assertTrue(textRun.isBullet());
114
115
		assertEquals("Numbered list between two bulleted lists\rSecond numbered list item", textRuns[1].getRawText());
116
		assertEquals("Second bulleted list � should appear after numbered list\rMore bullets", textRuns[2].getRawText());
117
		
118
		final EscherTextboxWrapper[] styleAtoms = s.getTextboxWrappers();
119
		assertEquals(textRuns.length, styleAtoms.length);
120
		checkSingleRunWrapper(27, styleAtoms[0]);
121
		checkSingleRunWrapper(67, styleAtoms[1]);
122
		checkSingleRunWrapper(70, styleAtoms[2]);
123
	}
124
	private void checkSingleRunWrapper(final int exceptedLength, final EscherTextboxWrapper wrapper) {
125
		final StyleTextPropAtom styleTextPropAtom = wrapper.getStyleTextPropAtom();
126
		final List<TextPropCollection> textProps = styleTextPropAtom.getCharacterStyles();
127
		assertEquals(1, textProps.size());
128
		final TextPropCollection[] props = (TextPropCollection[]) textProps.toArray(new TextPropCollection[textProps.size()]);
129
		assertEquals(exceptedLength, props[0].getCharactersCovered());
130
	}
131
}
(-)src/scratchpad/src/org/apache/poi/hslf/model/Sheet.java (-8 / +29 lines)
Lines 122-134 Link Here
122
     */
122
     */
123
    public static TextRun[] findTextRuns(PPDrawing ppdrawing) {
123
    public static TextRun[] findTextRuns(PPDrawing ppdrawing) {
124
        final List<TextRun> runsV = new ArrayList<TextRun>();
124
        final List<TextRun> runsV = new ArrayList<TextRun>();
125
        EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
125
        final EscherTextboxWrapper[] wrappers = ppdrawing.getTextboxWrappers();
126
        for (int i = 0; i < wrappers.length; i++) {
126
        for (int i = 0; i < wrappers.length; i++) {
127
            int s1 = runsV.size();
127
            int s1 = runsV.size();
128
128
129
            // propagate parents to parent-aware records
129
            // propagate parents to parent-aware records
130
            RecordContainer.handleParentAwareRecords(wrappers[i]);
130
            RecordContainer.handleParentAwareRecords(wrappers[i]);
131
            findTextRuns(wrappers[i].getChildRecords(), runsV);
131
            findTextRuns(wrappers[i], runsV);
132
            int s2 = runsV.size();
132
            int s2 = runsV.size();
133
            if (s2 != s1){
133
            if (s2 != s1){
134
                TextRun t = runsV.get(runsV.size()-1);
134
                TextRun t = runsV.get(runsV.size()-1);
Lines 137-143 Link Here
137
        }
137
        }
138
        return runsV.toArray(new TextRun[runsV.size()]);
138
        return runsV.toArray(new TextRun[runsV.size()]);
139
    }
139
    }
140
141
    /**
140
    /**
142
     * Scans through the supplied record array, looking for
141
     * Scans through the supplied record array, looking for
143
     * a TextHeaderAtom followed by one of a TextBytesAtom or
142
     * a TextHeaderAtom followed by one of a TextBytesAtom or
Lines 146-153 Link Here
146
     * @param records the records to build from
145
     * @param records the records to build from
147
     * @param found   vector to add any found to
146
     * @param found   vector to add any found to
148
     */
147
     */
149
    protected static void findTextRuns(Record[] records, List<TextRun> found) {
148
    protected static void findTextRuns(final Record[] records, final List<TextRun> found) {
150
        // Look for a TextHeaderAtom
149
    	findTextRuns(records, found, null); 
150
    }
151
    /**
152
     * Scans through the supplied record array, looking for
153
     * a TextHeaderAtom followed by one of a TextBytesAtom or
154
     * a TextCharsAtom. Builds up TextRuns from these
155
     *
156
     * @param wrapper an EscherTextboxWrapper
157
     * @param found   vector to add any found to
158
     */
159
    protected static void findTextRuns(final EscherTextboxWrapper wrapper, final List<TextRun> found) {
160
    	findTextRuns(wrapper.getChildRecords(), found, wrapper.getStyleTextProp9Atom());
161
    }
162
    /**
163
     * Scans through the supplied record array, looking for
164
     * a TextHeaderAtom followed by one of a TextBytesAtom or
165
     * a TextCharsAtom. Builds up TextRuns from these
166
     *
167
     * @param records the records to build from
168
     * @param found   vector to add any found to
169
     * @param styleTextProp9Atom a StyleTextProp9Atom with numbered lists info
170
     */
171
    protected static void findTextRuns(final Record[] records, final List<TextRun> found, final StyleTextProp9Atom styleTextProp9Atom) {
151
        for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) {
172
        for (int i = 0, slwtIndex=0; i < (records.length - 1); i++) {
152
            if (records[i] instanceof TextHeaderAtom) {
173
            if (records[i] instanceof TextHeaderAtom) {
153
                TextRun trun = null;
174
                TextRun trun = null;
Lines 169-175 Link Here
169
                    TextBytesAtom tba = (TextBytesAtom) records[i + 1];
190
                    TextBytesAtom tba = (TextBytesAtom) records[i + 1];
170
                    trun = new TextRun(tha, tba, stpa);
191
                    trun = new TextRun(tha, tba, stpa);
171
                } else if (records[i + 1].getRecordType() == 4001l) {
192
                } else if (records[i + 1].getRecordType() == 4001l) {
172
                    // StyleTextPropAtom - Safe to ignore
193
                	stpa = (StyleTextPropAtom) records[i + 1];
173
                } else if (records[i + 1].getRecordType() == 4010l) {
194
                } else if (records[i + 1].getRecordType() == 4010l) {
174
                    // TextSpecInfoAtom - Safe to ignore
195
                    // TextSpecInfoAtom - Safe to ignore
175
                } else {
196
                } else {
Lines 177-183 Link Here
177
                }
198
                }
178
199
179
                if (trun != null) {
200
                if (trun != null) {
180
                    ArrayList lst = new ArrayList();
201
                    List<Record> lst = new ArrayList<Record>();
181
                    for (int j = i; j < records.length; j++) {
202
                    for (int j = i; j < records.length; j++) {
182
                        if(j > i && records[j] instanceof TextHeaderAtom) break;
203
                        if(j > i && records[j] instanceof TextHeaderAtom) break;
183
                        lst.add(records[j]);
204
                        lst.add(records[j]);
Lines 186-192 Link Here
186
                    lst.toArray(recs);
207
                    lst.toArray(recs);
187
                    trun._records = recs;
208
                    trun._records = recs;
188
                    trun.setIndex(slwtIndex);
209
                    trun.setIndex(slwtIndex);
189
210
                    trun.setStyleTextProp9Atom(styleTextProp9Atom);
190
                    found.add(trun);
211
                    found.add(trun);
191
                    i++;
212
                    i++;
192
                } else {
213
                } else {
(-)src/scratchpad/src/org/apache/poi/hslf/record/RecordTypes.java (-2 / +3 lines)
Lines 84-90 Link Here
84
    public static final Type OutlineTextRefAtom = new Type(3998,OutlineTextRefAtom.class);
84
    public static final Type OutlineTextRefAtom = new Type(3998,OutlineTextRefAtom.class);
85
    public static final Type TextHeaderAtom = new Type(3999,TextHeaderAtom.class);
85
    public static final Type TextHeaderAtom = new Type(3999,TextHeaderAtom.class);
86
    public static final Type TextCharsAtom = new Type(4000,TextCharsAtom.class);
86
    public static final Type TextCharsAtom = new Type(4000,TextCharsAtom.class);
87
    public static final Type StyleTextPropAtom = new Type(4001,StyleTextPropAtom.class);
87
    public static final Type StyleTextPropAtom = new Type(4001, StyleTextPropAtom.class);//0x0fa1 RT_StyleTextPropAtom
88
    public static final Type BaseTextPropAtom = new Type(4002,null);
88
    public static final Type BaseTextPropAtom = new Type(4002,null);
89
    public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
89
    public static final Type TxMasterStyleAtom = new Type(4003,TxMasterStyleAtom.class);
90
    public static final Type TxCFStyleAtom = new Type(4004,null);
90
    public static final Type TxCFStyleAtom = new Type(4004,null);
Lines 95-100 Link Here
95
    public static final Type TxSIStyleAtom = new Type(4009,null);
95
    public static final Type TxSIStyleAtom = new Type(4009,null);
96
    public static final Type TextSpecInfoAtom = new Type(4010, TextSpecInfoAtom.class);
96
    public static final Type TextSpecInfoAtom = new Type(4010, TextSpecInfoAtom.class);
97
    public static final Type DefaultRulerAtom = new Type(4011,null);
97
    public static final Type DefaultRulerAtom = new Type(4011,null);
98
    public static final Type StyleTextProp9Atom = new Type(4012, StyleTextProp9Atom.class); //0x0FAC RT_StyleTextProp9Atom
98
    public static final Type FontEntityAtom = new Type(4023,FontEntityAtom.class);
99
    public static final Type FontEntityAtom = new Type(4023,FontEntityAtom.class);
99
    public static final Type FontEmbeddedData = new Type(4024,null);
100
    public static final Type FontEmbeddedData = new Type(4024,null);
100
    public static final Type CString = new Type(4026,CString.class);
101
    public static final Type CString = new Type(4026,CString.class);
Lines 146-152 Link Here
146
    public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class);
147
    public static final Type ProgTags = new Type(5000,DummyPositionSensitiveRecordWithChildren.class);
147
    public static final Type ProgStringTag = new Type(5001,null);
148
    public static final Type ProgStringTag = new Type(5001,null);
148
    public static final Type ProgBinaryTag = new Type(5002,DummyPositionSensitiveRecordWithChildren.class);
149
    public static final Type ProgBinaryTag = new Type(5002,DummyPositionSensitiveRecordWithChildren.class);
149
    public static final Type BinaryTagData = new Type(5003,DummyPositionSensitiveRecordWithChildren.class);
150
    public static final Type BinaryTagData = new Type(5003, BinaryTagDataBlob.class);//0x138b RT_BinaryTagDataBlob
150
    public static final Type PrpublicintOptions = new Type(6000,null);
151
    public static final Type PrpublicintOptions = new Type(6000,null);
151
    public static final Type PersistPtrFullBlock = new Type(6001,PersistPtrHolder.class);
152
    public static final Type PersistPtrFullBlock = new Type(6001,PersistPtrHolder.class);
152
    public static final Type PersistPtrIncrementalBlock = new Type(6002,PersistPtrHolder.class);
153
    public static final Type PersistPtrIncrementalBlock = new Type(6002,PersistPtrHolder.class);
(-)src/scratchpad/src/org/apache/poi/hslf/record/EscherTextboxWrapper.java (+16 lines)
Lines 36-41 Link Here
36
	private EscherTextboxRecord _escherRecord;
36
	private EscherTextboxRecord _escherRecord;
37
	private long _type;
37
	private long _type;
38
	private int shapeId;
38
	private int shapeId;
39
	private StyleTextPropAtom styleTextPropAtom;
40
	private StyleTextProp9Atom styleTextProp9Atom;
39
41
40
	/**
42
	/**
41
	 * Returns the underlying DDF Escher Record
43
	 * Returns the underlying DDF Escher Record
Lines 52-57 Link Here
52
		// Find the child records in the escher data
54
		// Find the child records in the escher data
53
		byte[] data = _escherRecord.getData();
55
		byte[] data = _escherRecord.getData();
54
		_children = Record.findChildRecords(data,0,data.length);
56
		_children = Record.findChildRecords(data,0,data.length);
57
		for (Record r : this._children) {
58
			if (r instanceof StyleTextPropAtom) { this.styleTextPropAtom = (StyleTextPropAtom) r; }
59
		}
55
	}
60
	}
56
61
57
	/**
62
	/**
Lines 104-107 Link Here
104
	public void setShapeId(int id){
109
	public void setShapeId(int id){
105
		shapeId = id;
110
		shapeId = id;
106
	}
111
	}
112
113
	public StyleTextPropAtom getStyleTextPropAtom() {
114
		return styleTextPropAtom;
115
	}
116
117
	public void setStyleTextProp9Atom(final StyleTextProp9Atom nineAtom) {
118
		this.styleTextProp9Atom = nineAtom;
119
	}
120
	public StyleTextProp9Atom getStyleTextProp9Atom() {
121
		return this.styleTextProp9Atom;
122
	}
107
}
123
}
(-)src/scratchpad/src/org/apache/poi/hslf/model/TextRun.java (+15 lines)
Lines 54-59 Link Here
54
     * (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
54
     * (there can be misc InteractiveInfo, TxInteractiveInfo and other records)
55
     */
55
     */
56
    protected Record[] _records;
56
    protected Record[] _records;
57
	private StyleTextPropAtom styleTextPropAtom;
58
	private StyleTextProp9Atom styleTextProp9Atom;
57
59
58
	/**
60
	/**
59
	* Constructs a Text Run from a Unicode text block
61
	* Constructs a Text Run from a Unicode text block
Lines 702-706 Link Here
702
    public Record[] getRecords(){
704
    public Record[] getRecords(){
703
        return _records;
705
        return _records;
704
    }
706
    }
707
    /** Numbered List info */
708
	public void setStyleTextProp9Atom(final StyleTextProp9Atom styleTextProp9Atom) {
709
		this.styleTextProp9Atom = styleTextProp9Atom;
710
	}
711
    /** Numbered List info */
712
	public StyleTextProp9Atom getStyleTextProp9Atom() {
713
		return this.styleTextProp9Atom;
714
	}
715
716
    /** Characters covered */
717
	public StyleTextPropAtom getStyleTextPropAtom() {
718
		return this._styleAtom;		
719
	}
705
720
706
}
721
}
(-)src/scratchpad/src/org/apache/poi/hslf/record/TextAutoNumberSchemeEnum.java (+109 lines)
Line 0 Link Here
1
package org.apache.poi.hslf.record;
2
3
public enum TextAutoNumberSchemeEnum {
4
	//Name Value Meaning
5
	ANM_AlphaLcPeriod 			((short) 0x0000), // "Lowercase Latin character followed by a period. Example: a., b., c., ..."),
6
	ANM_AlphaUcPeriod 			((short) 0x0001), // "Uppercase Latin character followed by a period. Example: A., B., C., ..."),
7
	ANM_ArabicParenRight		((short) 0x0002), // "Arabic numeral followed by a closing parenthesis. Example: 1), 2), 3), ..."),
8
	ANM_ArabicPeriod			((short) 0x0003), // "Arabic numeral followed by a period. Example: 1., 2., 3., ..."),
9
	ANM_RomanLcParenBoth		((short) 0x0004), // "Lowercase Roman numeral enclosed in parentheses. Example: (i), (ii), (iii), ..."),            
10
	ANM_RomanLcParenRight		((short) 0x0005), // "Lowercase Roman numeral followed by a closing parenthesis. Example: i), ii), iii), ..."),     
11
	ANM_RomanLcPeriod			((short) 0x0006), // "Lowercase Roman numeral followed by a period. Example: i., ii., iii., ..."), 
12
	ANM_RomanUcPeriod			((short) 0x0007), // "Uppercase Roman numeral followed by a period. Example: I., II., III., ..."),
13
	ANM_AlphaLcParenBoth		((short) 0x0008), // "Lowercase alphabetic character enclosed in parentheses. Example: (a), (b), (c), ..."),
14
	ANM_AlphaLcParenRight		((short) 0x0009), // "Lowercase alphabetic character followed by a closing parenthesis. Example: a), b), c), ..."),
15
	ANM_AlphaUcParenBoth		((short) 0x000A), // "Uppercase alphabetic character enclosed in parentheses. Example: (A), (B), (C), ..."),
16
	ANM_AlphaUcParenRight		((short) 0x000B), // "Uppercase alphabetic character followed by a closing parenthesis. Example: A), B), C), ..."), 
17
	ANM_ArabicParenBoth			((short) 0x000C), // "Arabic numeral enclosed in parentheses. Example: (1), (2), (3), ..."),
18
	ANM_ArabicPlain				((short) 0x000D), // "Arabic numeral. Example: 1, 2, 3, ..."),
19
	ANM_RomanUcParenBoth		((short) 0x000E), // "Uppercase Roman numeral enclosed in parentheses. Example: (I), (II), (III), ..."),
20
	ANM_RomanUcParenRight		((short) 0x000F), // "Uppercase Roman numeral followed by a closing parenthesis. Example: I), II), III), ..."),
21
	ANM_ChsPlain				((short) 0x0010), // "Simplified Chinese."),
22
	ANM_ChsPeriod				((short) 0x0011), // "Simplified Chinese with single-byte period."),
23
	ANM_CircleNumDBPlain		((short) 0x0012), // "Double byte circle numbers."),
24
	ANM_CircleNumWDBWhitePlain	((short) 0x0013), // "Wingdings white circle numbers."),
25
	ANM_CircleNumWDBBlackPlain	((short) 0x0014), // "Wingdings black circle numbers."),
26
	ANM_ChtPlain				((short) 0x0015), // "Traditional Chinese."),
27
	ANM_ChtPeriod				((short) 0x0016), // "Traditional Chinese with single-byte period."),
28
	ANM_Arabic1Minus			((short) 0x0017), // "Bidi Arabic 1 (AraAlpha) with ANSI minus symbol."),
29
	ANM_Arabic2Minus			((short) 0x0018), // "Bidi Arabic 2 (AraAbjad) with ANSI minus symbol."),
30
	ANM_Hebrew2Minus			((short) 0x0019), // "Bidi Hebrew 2 with ANSI minus symbol."),
31
	ANM_JpnKorPlain				((short) 0x001A), // "Japanese/Korean."),
32
	ANM_JpnKorPeriod			((short) 0x001B), // "Japanese/Korean with single-byte period."),
33
	ANM_ArabicDbPlain			((short) 0x001C), // "Double-byte Arabic numbers."),
34
	ANM_ArabicDbPeriod			((short) 0x001D), // "Double-byte Arabic numbers with double-byte period."),
35
	ANM_ThaiAlphaPeriod			((short) 0x001E), // "Thai alphabetic character followed by a period."),
36
	ANM_ThaiAlphaParenRight		((short) 0x001F), // "Thai alphabetic character followed by a closing parenthesis."),
37
	ANM_ThaiAlphaParenBoth		((short) 0x0020), // "Thai alphabetic character enclosed by parentheses."),
38
	ANM_ThaiNumPeriod			((short) 0x0021), // "Thai numeral followed by a period."),
39
	ANM_ThaiNumParenRight		((short) 0x0022), // "Thai numeral followed by a closing parenthesis."),
40
	ANM_ThaiNumParenBoth		((short) 0x0023), // "Thai numeral enclosed in parentheses."),
41
	ANM_HindiAlphaPeriod		((short) 0x0024), // "Hindi alphabetic character followed by a period."),
42
	ANM_HindiNumPeriod			((short) 0x0025), // "Hindi numeric character followed by a period."),
43
	ANM_JpnChsDBPeriod			((short) 0x0026), // "Japanese with double-byte period."),
44
	ANM_HindiNumParenRight		((short) 0x0027), // "Hindi numeric character followed by a closing parenthesis."),
45
	ANM_HindiAlpha1Period		((short) 0x0028); // "Hindi alphabetic character followed by a period.");
46
47
	private final short value;
48
	private TextAutoNumberSchemeEnum(final short code) {
49
		this.value = code;
50
	}
51
	private short getValue() { return value; }
52
	public String getDescription() {
53
		return TextAutoNumberSchemeEnum.getDescription(this);
54
	}
55
	public static String getDescription(final TextAutoNumberSchemeEnum code) {
56
		switch (code) {
57
		case ANM_AlphaLcPeriod			: return "Lowercase Latin character followed by a period. Example: a., b., c., ...";
58
		case ANM_AlphaUcPeriod 			: return "Uppercase Latin character followed by a period. Example: A., B., C., ...";
59
		case ANM_ArabicParenRight		: return "Arabic numeral followed by a closing parenthesis. Example: 1), 2), 3), ...";
60
		case ANM_ArabicPeriod			: return "Arabic numeral followed by a period. Example: 1., 2., 3., ...";
61
		case ANM_RomanLcParenBoth		: return "Lowercase Roman numeral enclosed in parentheses. Example: (i), (ii), (iii), ...";            
62
		case ANM_RomanLcParenRight		: return "Lowercase Roman numeral followed by a closing parenthesis. Example: i), ii), iii), ...";     
63
		case ANM_RomanLcPeriod			: return "Lowercase Roman numeral followed by a period. Example: i., ii., iii., ...";
64
		case ANM_RomanUcPeriod			: return "Uppercase Roman numeral followed by a period. Example: I., II., III., ...";
65
		case ANM_AlphaLcParenBoth		: return "Lowercase alphabetic character enclosed in parentheses. Example: (a), (b), (c), ...";
66
		case ANM_AlphaLcParenRight		: return "Lowercase alphabetic character followed by a closing parenthesis. Example: a), b), c), ...";
67
		case ANM_AlphaUcParenBoth		: return "Uppercase alphabetic character enclosed in parentheses. Example: (A), (B), (C), ...";
68
		case ANM_AlphaUcParenRight		: return "Uppercase alphabetic character followed by a closing parenthesis. Example: A), B), C), ..."; 
69
		case ANM_ArabicParenBoth		: return "Arabic numeral enclosed in parentheses. Example: (1), (2), (3), ...";
70
		case ANM_ArabicPlain			: return "Arabic numeral. Example: 1, 2, 3, ...";
71
		case ANM_RomanUcParenBoth		: return "Uppercase Roman numeral enclosed in parentheses. Example: (I), (II), (III), ...";
72
		case ANM_RomanUcParenRight		: return "Uppercase Roman numeral followed by a closing parenthesis. Example: I), II), III), ...";
73
		case ANM_ChsPlain				: return "Simplified Chinese.";
74
		case ANM_ChsPeriod				: return "Simplified Chinese with single-byte period.";
75
		case ANM_CircleNumDBPlain		: return "Double byte circle numbers.";
76
		case ANM_CircleNumWDBWhitePlain	: return "Wingdings white circle numbers.";
77
		case ANM_CircleNumWDBBlackPlain	: return "Wingdings black circle numbers.";
78
		case ANM_ChtPlain				: return "Traditional Chinese.";
79
		case ANM_ChtPeriod				: return "Traditional Chinese with single-byte period.";
80
		case ANM_Arabic1Minus			: return "Bidi Arabic 1 (AraAlpha) with ANSI minus symbol.";
81
		case ANM_Arabic2Minus			: return "Bidi Arabic 2 (AraAbjad) with ANSI minus symbol.";
82
		case ANM_Hebrew2Minus			: return "Bidi Hebrew 2 with ANSI minus symbol.";
83
		case ANM_JpnKorPlain			: return "Japanese/Korean.";
84
		case ANM_JpnKorPeriod			: return "Japanese/Korean with single-byte period.";
85
		case ANM_ArabicDbPlain			: return "Double-byte Arabic numbers.";
86
		case ANM_ArabicDbPeriod			: return "Double-byte Arabic numbers with double-byte period.";
87
		case ANM_ThaiAlphaPeriod		: return "Thai alphabetic character followed by a period.";
88
		case ANM_ThaiAlphaParenRight	: return "Thai alphabetic character followed by a closing parenthesis.";
89
		case ANM_ThaiAlphaParenBoth		: return "Thai alphabetic character enclosed by parentheses.";
90
		case ANM_ThaiNumPeriod			: return "Thai numeral followed by a period.";
91
		case ANM_ThaiNumParenRight		: return "Thai numeral followed by a closing parenthesis.";
92
		case ANM_ThaiNumParenBoth		: return "Thai numeral enclosed in parentheses.";
93
		case ANM_HindiAlphaPeriod		: return "Hindi alphabetic character followed by a period.";
94
		case ANM_HindiNumPeriod			: return "Hindi numeric character followed by a period.";
95
		case ANM_JpnChsDBPeriod			: return "Japanese with double-byte period.";
96
		case ANM_HindiNumParenRight		: return "Hindi numeric character followed by a closing parenthesis.";
97
		case ANM_HindiAlpha1Period		: return "Hindi alphabetic character followed by a period.";
98
		default							: return "Unknown Numbered Scheme";
99
		}
100
	}
101
	public static TextAutoNumberSchemeEnum valueOf(short autoNumberScheme) {
102
		for (TextAutoNumberSchemeEnum item: TextAutoNumberSchemeEnum.values()) {
103
			if (autoNumberScheme == item.getValue()) {
104
				return item;
105
			}
106
		}
107
		return null;
108
	}
109
}
(-)src/scratchpad/src/org/apache/poi/hslf/model/textproperties/TextPFException9.java (+117 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
/**
19
 * A structure that specifies additional paragraph-level formatting
20
 * such as Bullet Auto Number Scheme.
21
 */
22
package org.apache.poi.hslf.model.textproperties;
23
24
import org.apache.poi.hslf.record.TextAutoNumberSchemeEnum;
25
import org.apache.poi.util.LittleEndian;
26
27
/**
28
 * This structure store text autonumber scheme and start number.
29
 * If a paragraph has an autonumber(fBulletHasAutoNumber = 0x0001) but start number and scheme are empty,
30
 * this means the default values will be used: statNumber=1 and sheme=ANM_ArabicPeriod
31
 * @see http://social.msdn.microsoft.com/Forums/mr-IN/os_binaryfile/thread/650888db-fabd-4b95-88dc-f0455f6e2d28
32
 *
33
 * @author Alex Nikiforov [mailto:anikif@gmail.com]
34
 *
35
 */
36
public class TextPFException9 {
37
	//private final byte mask1;
38
	//private final byte mask2;
39
	private final byte mask3;
40
	private final byte mask4;
41
	private final Short bulletBlipRef;
42
	private final Short fBulletHasAutoNumber;
43
	private final TextAutoNumberSchemeEnum autoNumberScheme;
44
	private final static TextAutoNumberSchemeEnum DEFAULT_AUTONUMBER_SHEME = TextAutoNumberSchemeEnum.ANM_ArabicPeriod;
45
	private final Short autoNumberStartNumber;
46
	private final static Short DEFAULT_START_NUMBER = new Short((short)1);
47
	private final int recordLength;
48
	public TextPFException9(final byte[] source, final int startIndex) {
49
		//this.mask1 = source[startIndex];
50
		//this.mask2 = source[startIndex + 1];
51
		this.mask3 = source[startIndex + 2];
52
		this.mask4 = source[startIndex + 3];
53
		int length = 4;
54
		int index = startIndex + 4;
55
		if (0 == (mask3 & (byte)0x80 )) {
56
			this.bulletBlipRef = null;
57
		} else {
58
			this.bulletBlipRef = LittleEndian.getShort(source, index);
59
			index +=2;
60
			length = 6;
61
		}
62
		if (0 == (mask4 & 2)) {
63
			this.fBulletHasAutoNumber = null;
64
		} else {
65
			this.fBulletHasAutoNumber = LittleEndian.getShort(source, index);
66
			index +=2;
67
			length +=2;
68
		}
69
		if (0 == (mask4 & 1)) {
70
			this.autoNumberScheme = null;
71
			this.autoNumberStartNumber = null;
72
		} else {
73
			this.autoNumberScheme = TextAutoNumberSchemeEnum.valueOf(LittleEndian.getShort(source, index));
74
			index +=2;
75
			this.autoNumberStartNumber = LittleEndian.getShort(source, index);
76
			index +=2;
77
			length +=4;
78
		}
79
		this.recordLength = length;
80
	}
81
	public Short getBulletBlipRef() {
82
		return bulletBlipRef;
83
	}
84
	public Short getfBulletHasAutoNumber() {
85
		return fBulletHasAutoNumber;
86
	}
87
	public TextAutoNumberSchemeEnum getAutoNumberScheme() {
88
		if (null != this.autoNumberScheme) {
89
			return this.autoNumberScheme;
90
		}
91
		if (null != this.fBulletHasAutoNumber && 1 == this.fBulletHasAutoNumber.shortValue()) {
92
			return DEFAULT_AUTONUMBER_SHEME;
93
		}
94
		return null;
95
	}
96
	public Short getAutoNumberStartNumber() {
97
		if (null != this.autoNumberStartNumber) {
98
			return this.autoNumberStartNumber;
99
		}
100
		if (null != this.fBulletHasAutoNumber && 1 == this.fBulletHasAutoNumber.shortValue()) {
101
			return DEFAULT_START_NUMBER;
102
		}
103
		return null;
104
	}
105
	public int getRecordLength() {
106
		return recordLength;
107
	}
108
	@Override
109
	public String toString() {
110
		final StringBuilder sb = new StringBuilder("Record length: ").append(this.recordLength).append(" bytes\n");
111
		sb.append("bulletBlipRef: ").append(this.bulletBlipRef).append("\n");
112
		sb.append("fBulletHasAutoNumber: ").append(this.fBulletHasAutoNumber).append("\n");
113
		sb.append("autoNumberScheme: ").append(this.autoNumberScheme).append("\n");
114
		sb.append("autoNumberStartNumber: ").append(this.autoNumberStartNumber).append("\n");
115
		return sb.toString();
116
	}
117
}
(-)src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNumberedList3.java (+107 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.hslf.usermodel;
19
20
import java.util.List;
21
22
import junit.framework.TestCase;
23
24
import org.apache.poi.hslf.model.Slide;
25
import org.apache.poi.hslf.model.TextRun;
26
import org.apache.poi.hslf.model.textproperties.TextPFException9;
27
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
28
import org.apache.poi.hslf.record.EscherTextboxWrapper;
29
import org.apache.poi.hslf.record.StyleTextProp9Atom;
30
import org.apache.poi.hslf.record.StyleTextPropAtom;
31
import org.apache.poi.hslf.record.TextAutoNumberSchemeEnum;
32
import org.apache.poi.POIDataSamples;
33
34
35
/**
36
 * Test that checks numbered list functionality.
37
 * if a paragraph has autonumber ()
38
 * @see http://social.msdn.microsoft.com/Forums/mr-IN/os_binaryfile/thread/650888db-fabd-4b95-88dc-f0455f6e2d28
39
 * 
40
 * @author Alex Nikiforov [mailto:anikif@gmail.com]
41
 */
42
public final class TestNumberedList3 extends TestCase {
43
    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
44
45
	protected void setUp() throws Exception {
46
	}
47
48
	public void testNumberedList() throws Exception {
49
		SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("numbers3.ppt"));
50
		assertTrue("No Exceptions while reading file", true);
51
52
		final Slide[] slides = ppt.getSlides();
53
		assertEquals(1, slides.length);
54
		final Slide slide = slides[0];
55
		checkSlide(slide);
56
	}
57
	private void checkSlide(final Slide s) {
58
		final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();
59
		assertNotNull(numberedListArray);
60
		assertEquals(1, numberedListArray.length);
61
		final StyleTextProp9Atom numberedListInfoForTextBox = numberedListArray[0];
62
		assertNotNull(numberedListInfoForTextBox);
63
		final TextPFException9[] autoNumbersOfTextBox0 = numberedListInfoForTextBox.getAutoNumberTypes();
64
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox0[0].getfBulletHasAutoNumber());
65
		assertEquals(Short.valueOf((short)1), autoNumbersOfTextBox0[0].getAutoNumberStartNumber());//Default value = 1 will be used 
66
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox0[0].getAutoNumberScheme());
67
		
68
		final TextRun[] textRuns = s.getTextRuns();
69
		assertEquals(3, textRuns.length);
70
		assertEquals("Bulleted list\rMore bullets\rNo bullets here", textRuns[0].getRawText());
71
		assertEquals("Numbered list between two bulleted lists\rSecond numbered list item", textRuns[1].getRawText());
72
		assertEquals("Second bulleted list � should appear after numbered list\rMore bullets", textRuns[2].getRawText());
73
		assertEquals(2, textRuns[0].getRichTextRuns().length);
74
		assertEquals(1, textRuns[1].getRichTextRuns().length);
75
		assertEquals(1, textRuns[2].getRichTextRuns().length);
76
		assertNull(textRuns[0].getStyleTextProp9Atom());
77
		assertNotNull(textRuns[1].getStyleTextProp9Atom());
78
		assertNull(textRuns[2].getStyleTextProp9Atom());
79
		final TextPFException9[] autoNumbers = textRuns[1].getStyleTextProp9Atom().getAutoNumberTypes();
80
		assertEquals(1, autoNumbers.length);
81
		assertEquals(Short.valueOf((short)1), autoNumbers[0].getfBulletHasAutoNumber());
82
		assertEquals(Short.valueOf((short)1), autoNumbers[0].getAutoNumberStartNumber());//Default value = 1 will be used 
83
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbersOfTextBox0[0].getAutoNumberScheme());
84
		
85
		final List<TextPropCollection> textProps = textRuns[1].getStyleTextPropAtom().getCharacterStyles();
86
		assertEquals(1, textProps.size());
87
		final TextPropCollection textProp = textProps.get(0);
88
		assertEquals(67, textProp.getCharactersCovered());
89
		
90
		
91
		RichTextRun textRun = textRuns[0].getRichTextRuns()[0];
92
		assertTrue(textRun.isBullet());
93
94
		
95
		final EscherTextboxWrapper[] styleAtoms = s.getTextboxWrappers();
96
		assertEquals(textRuns.length, styleAtoms.length);
97
		checkSingleRunWrapper(43, styleAtoms[0]);
98
		checkSingleRunWrapper(67, styleAtoms[1]);
99
	}
100
	private void checkSingleRunWrapper(final int exceptedLength, final EscherTextboxWrapper wrapper) {
101
		final StyleTextPropAtom styleTextPropAtom = wrapper.getStyleTextPropAtom();
102
		final List<TextPropCollection> textProps = styleTextPropAtom.getCharacterStyles();
103
		assertEquals(1, textProps.size());
104
		final TextPropCollection[] props = (TextPropCollection[]) textProps.toArray(new TextPropCollection[textProps.size()]);
105
		assertEquals(exceptedLength, props[0].getCharactersCovered());
106
	}
107
}
(-)src/scratchpad/src/org/apache/poi/hslf/record/StyleTextProp9Atom.java (+136 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.hslf.record;
19
20
import java.io.IOException;
21
import java.io.OutputStream;
22
import java.util.LinkedList;
23
import java.util.List;
24
25
import org.apache.poi.hslf.model.textproperties.TextPFException9;
26
import org.apache.poi.util.LittleEndian;
27
28
/**
29
 * The atom record that specifies additional text formatting.
30
 *
31
 * @author Alex Nikiforov [mailto:anikif@gmail.com]
32
 */
33
public final class StyleTextProp9Atom extends RecordAtom {
34
	private final TextPFException9[] autoNumberSchemes;
35
    /** Record header. */
36
    private byte[] header;
37
    /** Record data. */
38
    private byte[] data;
39
    private short version;
40
    private short recordId;
41
    private int length;
42
    
43
    /**
44
     * Constructs the link related atom record from its
45
     *  source data.
46
     *
47
     * @param source the source data as a byte array.
48
     * @param start the start offset into the byte array.
49
     * @param len the length of the slice in the byte array.
50
     */
51
    protected StyleTextProp9Atom(byte[] source, int start, int len) {
52
        // Get the header.
53
    	final List<TextPFException9> schemes = new LinkedList<TextPFException9>();
54
        header = new byte[8];
55
        System.arraycopy(source,start, header,0,8);
56
        this.version  = LittleEndian.getShort(header, 0);
57
        this.recordId = LittleEndian.getShort(header, 2);
58
        this.length   = LittleEndian.getInt(header, 4);
59
        
60
        // Get the record data.
61
        data = new byte[len-8];
62
        System.arraycopy(source, start+8, data, 0, len-8);
63
        for (int i = 0; i < data.length; ) {
64
        	final TextPFException9 item = new TextPFException9(data, i);
65
        	schemes.add(item);
66
        	i += item.getRecordLength();
67
        	//int textCfException9 = LittleEndian.getInt(data, i );
68
        	//TODO analyze textCfException when have some test data
69
        	i += 4;
70
        	int textSiException = LittleEndian.getInt(data, i );
71
        	i +=  + 4;//TextCFException9 + SIException
72
        	if (0 != (textSiException & 0x40)) { 
73
        		i += 2; //skip fBidi 
74
        	}
75
        	if (i >= data.length) {
76
        		break;
77
        	}
78
        }
79
        this.autoNumberSchemes = (TextPFException9[]) schemes.toArray(new TextPFException9[schemes.size()]);
80
    }
81
82
	/**
83
     * Gets the record type.
84
     * @return the record type.
85
     */
86
    public long getRecordType() { return this.recordId; }
87
88
    public short getVersion() {
89
		return version;
90
	}
91
92
	public int getLength() {
93
		return length;
94
	}
95
	public TextPFException9[] getAutoNumberTypes() {
96
		return this.autoNumberSchemes;
97
	}
98
99
	/**
100
     * Write the contents of the record back, so it can be written
101
     * to disk
102
     *
103
     * @param out the output stream to write to.
104
     * @throws java.io.IOException if an error occurs.
105
     */
106
    public void writeOut(OutputStream out) throws IOException {
107
        out.write(header);
108
        out.write(data);
109
    }
110
111
    /**
112
     * Update the text length
113
     *
114
     * @param size the text length
115
     */
116
    public void setTextSize(int size){
117
        LittleEndian.putInt(data, 0, size);
118
    }
119
120
    /**
121
     * Reset the content to one info run with the default values
122
     * @param size  the site of parent text
123
     */
124
    public void reset(int size){
125
        data = new byte[10];
126
        // 01 00 00 00
127
        LittleEndian.putInt(data, 0, size);
128
        // 01 00 00 00
129
        LittleEndian.putInt(data, 4, 1); //mask
130
        // 00 00
131
        LittleEndian.putShort(data, 8, (short)0); //langId
132
133
        // Update the size (header bytes 5-8)
134
        LittleEndian.putInt(header, 4, data.length);
135
    }
136
}
(-)src/scratchpad/src/org/apache/poi/hslf/record/PPDrawing.java (-19 / +135 lines)
Lines 25-30 Link Here
25
25
26
import java.io.IOException;
26
import java.io.IOException;
27
import java.io.OutputStream;
27
import java.io.OutputStream;
28
import java.util.LinkedList;
28
import java.util.List;
29
import java.util.List;
29
import java.util.Vector;
30
import java.util.Vector;
30
import java.util.Iterator;
31
import java.util.Iterator;
Lines 78-106 Link Here
78
		_type = LittleEndian.getUShort(_header,2);
79
		_type = LittleEndian.getUShort(_header,2);
79
80
80
		// Get the contents for now
81
		// Get the contents for now
81
		byte[] contents = new byte[len];
82
		final byte[] contents = new byte[len];
82
		System.arraycopy(source,start,contents,0,len);
83
		System.arraycopy(source,start,contents,0,len);
83
84
84
85
		// Build up a tree of Escher records contained within
85
		// Build up a tree of Escher records contained within
86
		DefaultEscherRecordFactory erf = new DefaultEscherRecordFactory();
86
		final DefaultEscherRecordFactory erf = new DefaultEscherRecordFactory();
87
		Vector escherChildren = new Vector();
87
		final Vector<EscherRecord> escherChildren = new Vector<EscherRecord>();
88
		findEscherChildren(erf,contents,8,len-8,escherChildren);
88
		findEscherChildren(erf, contents, 8, len-8, escherChildren);
89
		this.childRecords = (EscherRecord[]) escherChildren.toArray(new EscherRecord[escherChildren.size()]);
89
90
90
		childRecords = new EscherRecord[escherChildren.size()];
91
		if (1 == this.childRecords.length && (short)0xf002 == this.childRecords[0].getRecordId() && this.childRecords[0] instanceof EscherContainerRecord) {
91
		for(int i=0; i<childRecords.length; i++) {
92
			this.textboxWrappers = findInDgContainer((EscherContainerRecord) this.childRecords[0]);
92
			childRecords[i] = (EscherRecord)escherChildren.get(i);
93
		} else {
94
			// Find and EscherTextboxRecord's, and wrap them up
95
			final Vector<EscherTextboxWrapper> textboxes = new Vector<EscherTextboxWrapper>();
96
			findEscherTextboxRecord(childRecords, textboxes);
97
			this.textboxWrappers = (EscherTextboxWrapper[]) textboxes.toArray(new EscherTextboxWrapper[textboxes.size()]);
93
		}
98
		}
94
99
	}
95
		// Find and EscherTextboxRecord's, and wrap them up
100
	private EscherTextboxWrapper[] findInDgContainer(final EscherContainerRecord escherContainerF002) {
96
		Vector textboxes = new Vector();
101
		final List<EscherTextboxWrapper> found = new LinkedList<EscherTextboxWrapper>();
97
		findEscherTextboxRecord(childRecords, textboxes);
102
		final EscherContainerRecord SpgrContainer = findFirstEscherContainerRecordOfType((short)0xf003, escherContainerF002);
98
		textboxWrappers = new EscherTextboxWrapper[textboxes.size()];
103
		final EscherContainerRecord[] escherContainersF004 = findAllEscherContainerRecordOfType((short)0xf004, SpgrContainer);
99
		for(int i=0; i<textboxWrappers.length; i++) {
104
		for (EscherContainerRecord spContainer : escherContainersF004) {
100
			textboxWrappers[i] = (EscherTextboxWrapper)textboxes.get(i);
105
			StyleTextProp9Atom nineAtom = findInSpContainer(spContainer);
106
			EscherSpRecord sp = null;
107
			final EscherRecord escherContainerF00A = findFirstEscherRecordOfType((short)0xf00a, spContainer);
108
			if (null != escherContainerF00A) {
109
				if (escherContainerF00A instanceof EscherSpRecord) {
110
					sp = (EscherSpRecord) escherContainerF00A;
111
				}
112
			}
113
			final EscherRecord escherContainerF00D = findFirstEscherRecordOfType((short)0xf00d, spContainer);
114
			if (null == escherContainerF00D) { continue; }
115
			if (escherContainerF00D instanceof EscherTextboxRecord) {
116
				EscherTextboxRecord tbr = (EscherTextboxRecord) escherContainerF00D;
117
				EscherTextboxWrapper w = new EscherTextboxWrapper(tbr);
118
				w.setStyleTextProp9Atom(nineAtom);
119
				if (null != sp) {
120
					w.setShapeId(sp.getShapeId());
121
				}
122
				found.add(w);
123
			}
101
		}
124
		}
125
		return (EscherTextboxWrapper[]) found.toArray(new EscherTextboxWrapper[found.size()]);
102
	}
126
	}
103
127
	private StyleTextProp9Atom findInSpContainer(final EscherContainerRecord spContainer) {
128
		final EscherContainerRecord escherContainerF011 = findFirstEscherContainerRecordOfType((short)0xf011, spContainer);
129
		if (null == escherContainerF011) { return null; }
130
		final EscherContainerRecord escherContainer1388 = findFirstEscherContainerRecordOfType((short)0x1388, escherContainerF011);
131
		if (null == escherContainer1388) { return null; }
132
		final EscherContainerRecord escherContainer138A = findFirstEscherContainerRecordOfType((short)0x138A, escherContainer1388);
133
		if (null == escherContainer138A) { return null; }
134
		int size = escherContainer138A.getChildRecords().size();
135
		if (2 != size) { return null; }
136
		final Record r0 = buildFromUnknownEscherRecord((UnknownEscherRecord) escherContainer138A.getChild(0));
137
		final Record r1 = buildFromUnknownEscherRecord((UnknownEscherRecord) escherContainer138A.getChild(1));
138
		if (!(r0 instanceof CString)) { return null; }
139
		if (!("___PPT9".equals(((CString) r0).getText()))) { return null; };
140
		if (!(r1 instanceof BinaryTagDataBlob )) { return null; }
141
		final BinaryTagDataBlob blob = (BinaryTagDataBlob) r1;
142
		if (1 != blob.getChildRecords().length) { return null; }
143
		return (StyleTextProp9Atom) blob.findFirstOfType(0x0FACL);
144
	}
104
	/**
145
	/**
105
	 * Creates a new, empty, PPDrawing (typically for use with a new Slide
146
	 * Creates a new, empty, PPDrawing (typically for use with a new Slide
106
	 *  or Notes)
147
	 *  or Notes)
Lines 118-124 Link Here
118
	/**
159
	/**
119
	 * Tree walking way of finding Escher Child Records
160
	 * Tree walking way of finding Escher Child Records
120
	 */
161
	 */
121
	private void findEscherChildren(DefaultEscherRecordFactory erf, byte[] source, int startPos, int lenToGo, Vector found) {
162
	private void findEscherChildren(DefaultEscherRecordFactory erf, byte[] source, int startPos, int lenToGo, Vector<EscherRecord> found) {
122
163
123
		int escherBytes = LittleEndian.getInt( source, startPos + 4 ) + 8;
164
		int escherBytes = LittleEndian.getInt( source, startPos + 4 ) + 8;
124
165
Lines 138-144 Link Here
138
		/**
179
		/**
139
		 * Sanity check. Always advance the cursor by the correct value.
180
		 * Sanity check. Always advance the cursor by the correct value.
140
		 *
181
		 *
141
		 * getRecordSize() must return exatcly the same number of bytes that was written in fillFields.
182
		 * getRecordSize() must return exactly the same number of bytes that was written in fillFields.
142
		 * Sometimes it is not so, see an example in bug #44770. Most likely reason is that one of ddf records calculates wrong size.
183
		 * Sometimes it is not so, see an example in bug #44770. Most likely reason is that one of ddf records calculates wrong size.
143
		 */
184
		 */
144
		if(size != escherBytes){
185
		if(size != escherBytes){
Lines 155-161 Link Here
155
	/**
196
	/**
156
	 * Look for EscherTextboxRecords
197
	 * Look for EscherTextboxRecords
157
	 */
198
	 */
158
	private void findEscherTextboxRecord(EscherRecord[] toSearch, Vector found) {
199
	private void findEscherTextboxRecord(EscherRecord[] toSearch, Vector<EscherTextboxWrapper> found) {
159
		for(int i=0; i<toSearch.length; i++) {
200
		for(int i=0; i<toSearch.length; i++) {
160
			if(toSearch[i] instanceof EscherTextboxRecord) {
201
			if(toSearch[i] instanceof EscherTextboxRecord) {
161
				EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i];
202
				EscherTextboxRecord tbr = (EscherTextboxRecord)toSearch[i];
Lines 313-316 Link Here
313
		}
354
		}
314
		return dg;
355
		return dg;
315
	}
356
	}
357
358
    protected EscherContainerRecord findFirstEscherContainerRecordOfType(short type, EscherContainerRecord parent) {
359
    	if (null == parent) { return null; }
360
		final List<EscherContainerRecord> children = parent.getChildContainers();
361
		for (EscherContainerRecord child : children) {
362
			if (type == child.getRecordId()) {
363
				return child;
364
			}
365
		}
366
		return null;
367
    }
368
    protected EscherRecord findFirstEscherRecordOfType(short type, EscherContainerRecord parent) {
369
    	if (null == parent) { return null; }
370
		final List<EscherRecord> children = parent.getChildRecords();
371
		for (EscherRecord child : children) {
372
			if (type == child.getRecordId()) {
373
				return child;
374
			}
375
		}
376
		return null;
377
    }
378
    protected EscherContainerRecord[] findAllEscherContainerRecordOfType(short type, EscherContainerRecord parent) {
379
    	if (null == parent) { return new EscherContainerRecord[0]; }
380
		final List<EscherContainerRecord> children = parent.getChildContainers();
381
		final List<EscherContainerRecord> result = new LinkedList<EscherContainerRecord>();
382
		for (EscherContainerRecord child : children) {
383
			if (type == child.getRecordId()) {
384
				result.add(child);
385
			}
386
		}
387
		return (EscherContainerRecord[]) result.toArray(new EscherContainerRecord[result.size()]);
388
    }
389
    protected Record buildFromUnknownEscherRecord(UnknownEscherRecord unknown) {
390
		byte[] bingo = unknown.getData();
391
		byte[] restoredRecord = new byte[8 + bingo.length];
392
		System.arraycopy(bingo, 0, restoredRecord, 8, bingo.length);
393
		short recordVersion = unknown.getVersion();
394
		short recordId = unknown.getRecordId();
395
		int recordLength = unknown.getRecordSize();
396
		LittleEndian.putShort(restoredRecord, 0, recordVersion);
397
		LittleEndian.putShort(restoredRecord, 2, recordId);
398
		LittleEndian.putInt(restoredRecord, 4, recordLength);
399
		return Record.createRecordForType(recordId, restoredRecord, 0, restoredRecord.length);
400
    }
401
402
    public StyleTextProp9Atom[] getNumberedListInfo() {
403
    	final List<StyleTextProp9Atom> result = new LinkedList<StyleTextProp9Atom>();
404
    	EscherRecord[] escherRecords = this.getEscherRecords();
405
    	for (EscherRecord escherRecord : escherRecords) {
406
			if (escherRecord instanceof EscherContainerRecord && (short)0xf002 == escherRecord.getRecordId()) {
407
				EscherContainerRecord escherContainerF002 = (EscherContainerRecord) escherRecord;
408
				final EscherContainerRecord escherContainerF003 = findFirstEscherContainerRecordOfType((short)0xf003, escherContainerF002);
409
				final EscherContainerRecord[] escherContainersF004 = findAllEscherContainerRecordOfType((short)0xf004, escherContainerF003);
410
				for (EscherContainerRecord containerF004 : escherContainersF004) {
411
					final EscherContainerRecord escherContainerF011 = findFirstEscherContainerRecordOfType((short)0xf011, containerF004);
412
					if (null == escherContainerF011) { continue; }
413
					final EscherContainerRecord escherContainer1388 = findFirstEscherContainerRecordOfType((short)0x1388, escherContainerF011);
414
					if (null == escherContainer1388) { continue; }
415
					final EscherContainerRecord escherContainer138A = findFirstEscherContainerRecordOfType((short)0x138A, escherContainer1388);
416
					if (null == escherContainer138A) { continue; }
417
					int size = escherContainer138A.getChildRecords().size();
418
					if (2 != size) { continue; }
419
					final Record r0 = buildFromUnknownEscherRecord((UnknownEscherRecord) escherContainer138A.getChild(0));
420
					final Record r1 = buildFromUnknownEscherRecord((UnknownEscherRecord) escherContainer138A.getChild(1));
421
					if (!(r0 instanceof CString)) { continue; }
422
					if (!("___PPT9".equals(((CString) r0).getText()))) { continue; };
423
					if (!(r1 instanceof BinaryTagDataBlob )) { continue; }
424
					final BinaryTagDataBlob blob = (BinaryTagDataBlob) r1;
425
					if (1 != blob.getChildRecords().length) { continue; }
426
					result.add((StyleTextProp9Atom) blob.findFirstOfType(0x0FACL));
427
				}
428
			}
429
    	}
430
    	return (StyleTextProp9Atom[]) result.toArray(new StyleTextProp9Atom[result.size()]);
431
	}
316
}
432
}
(-)src/scratchpad/src/org/apache/poi/hslf/model/Slide.java (-3 / +15 lines)
Lines 18-24 Link Here
18
package org.apache.poi.hslf.model;
18
package org.apache.poi.hslf.model;
19
19
20
import java.awt.Graphics2D;
20
import java.awt.Graphics2D;
21
import java.util.Vector;
21
import java.util.LinkedList;
22
import java.util.List;
22
23
23
import org.apache.poi.ddf.EscherContainerRecord;
24
import org.apache.poi.ddf.EscherContainerRecord;
24
import org.apache.poi.ddf.EscherDgRecord;
25
import org.apache.poi.ddf.EscherDgRecord;
Lines 26-36 Link Here
26
import org.apache.poi.ddf.EscherSpRecord;
27
import org.apache.poi.ddf.EscherSpRecord;
27
import org.apache.poi.hslf.record.ColorSchemeAtom;
28
import org.apache.poi.hslf.record.ColorSchemeAtom;
28
import org.apache.poi.hslf.record.Comment2000;
29
import org.apache.poi.hslf.record.Comment2000;
30
import org.apache.poi.hslf.record.EscherTextboxWrapper;
29
import org.apache.poi.hslf.record.HeadersFootersContainer;
31
import org.apache.poi.hslf.record.HeadersFootersContainer;
30
import org.apache.poi.hslf.record.Record;
32
import org.apache.poi.hslf.record.Record;
31
import org.apache.poi.hslf.record.RecordContainer;
33
import org.apache.poi.hslf.record.RecordContainer;
32
import org.apache.poi.hslf.record.RecordTypes;
34
import org.apache.poi.hslf.record.RecordTypes;
33
import org.apache.poi.hslf.record.SlideAtom;
35
import org.apache.poi.hslf.record.SlideAtom;
36
import org.apache.poi.hslf.record.StyleTextProp9Atom;
34
import org.apache.poi.hslf.record.TextHeaderAtom;
37
import org.apache.poi.hslf.record.TextHeaderAtom;
35
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
38
import org.apache.poi.hslf.record.SlideListWithText.SlideAtomsSet;
36
39
Lines 53-59 Link Here
53
	/**
56
	/**
54
	 * Constructs a Slide from the Slide record, and the SlideAtomsSet
57
	 * Constructs a Slide from the Slide record, and the SlideAtomsSet
55
	 *  containing the text.
58
	 *  containing the text.
56
	 * Initialises TextRuns, to provide easier access to the text
59
	 * Initializes TextRuns, to provide easier access to the text
57
	 *
60
	 *
58
	 * @param slide the Slide record we're based on
61
	 * @param slide the Slide record we're based on
59
	 * @param notes the Notes sheet attached to us
62
	 * @param notes the Notes sheet attached to us
Lines 72-78 Link Here
72
		// For the text coming in from the SlideAtomsSet:
75
		// For the text coming in from the SlideAtomsSet:
73
		// Build up TextRuns from pairs of TextHeaderAtom and
76
		// Build up TextRuns from pairs of TextHeaderAtom and
74
		//  one of TextBytesAtom or TextCharsAtom
77
		//  one of TextBytesAtom or TextCharsAtom
75
		Vector textRuns = new Vector();
78
		final List<TextRun> textRuns = new LinkedList<TextRun>();
76
		if(_atomSet != null) {
79
		if(_atomSet != null) {
77
			findTextRuns(_atomSet.getSlideRecords(),textRuns);
80
			findTextRuns(_atomSet.getSlideRecords(),textRuns);
78
		} else {
81
		} else {
Lines 476-479 Link Here
476
            _runs = tmp;
479
            _runs = tmp;
477
        }
480
        }
478
    }
481
    }
482
483
    /** This will return an atom per TextBox, so if the page has two text boxes the method should return two atoms. */
484
    public StyleTextProp9Atom[] getNumberedListInfo() {
485
    	return this.getPPDrawing().getNumberedListInfo();
486
    }
487
488
	public EscherTextboxWrapper[] getTextboxWrappers() {
489
		return this.getPPDrawing().getTextboxWrappers();
490
	}
479
}
491
}
(-)src/scratchpad/src/org/apache/poi/hslf/record/BinaryTagDataBlob.java (+67 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.hslf.record;
19
20
import org.apache.poi.util.LittleEndian;
21
import java.io.IOException;
22
import java.io.OutputStream;
23
24
/**
25
 * If we come across a record we know has children of (potential)
26
 *  interest, but where the record itself is boring, but where other
27
 *  records may care about where this one lives, we create one
28
 *  of these. It allows us to get at the children, and track where on
29
 *  disk this is, but not much else.
30
 * Anything done using this should quite quickly be transitioned to its
31
 *  own proper record class!
32
 *
33
 * @author Nick Burch
34
 */
35
36
public final class BinaryTagDataBlob extends PositionDependentRecordContainer
37
{
38
	private byte[] _header;
39
	private long _type;
40
41
	/**
42
	 * Create a new holder for a boring record with children, but with
43
	 *  position dependent characteristics
44
	 */
45
	protected BinaryTagDataBlob(byte[] source, int start, int len) {
46
		// Just grab the header, not the whole contents
47
		_header = new byte[8];
48
		System.arraycopy(source,start,_header,0,8);
49
		_type = LittleEndian.getUShort(_header,2);
50
51
		// Find our children
52
		_children = Record.findChildRecords(source,start+8,len-8);
53
	}
54
55
	/**
56
	 * Return the value we were given at creation
57
	 */
58
	public long getRecordType() { return _type; }
59
60
	/**
61
	 * Write the contents of the record back, so it can be written
62
	 *  to disk
63
	 */
64
	public void writeOut(OutputStream out) throws IOException {
65
		writeOut(_header[0],_header[1],_type,_children,out);
66
	}
67
}
(-)src/scratchpad/testcases/org/apache/poi/hslf/usermodel/TestNumberedList.java (+128 lines)
Line 0 Link Here
1
/* ====================================================================
2
   Licensed to the Apache Software Foundation (ASF) under one or more
3
   contributor license agreements.  See the NOTICE file distributed with
4
   this work for additional information regarding copyright ownership.
5
   The ASF licenses this file to You under the Apache License, Version 2.0
6
   (the "License"); you may not use this file except in compliance with
7
   the License.  You may obtain a copy of the License at
8
9
       http://www.apache.org/licenses/LICENSE-2.0
10
11
   Unless required by applicable law or agreed to in writing, software
12
   distributed under the License is distributed on an "AS IS" BASIS,
13
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
   See the License for the specific language governing permissions and
15
   limitations under the License.
16
==================================================================== */
17
18
package org.apache.poi.hslf.usermodel;
19
20
import java.util.List;
21
22
import junit.framework.TestCase;
23
24
import org.apache.poi.hslf.model.Slide;
25
import org.apache.poi.hslf.model.TextRun;
26
import org.apache.poi.hslf.model.textproperties.TextPFException9;
27
import org.apache.poi.hslf.model.textproperties.TextPropCollection;
28
import org.apache.poi.hslf.record.EscherTextboxWrapper;
29
import org.apache.poi.hslf.record.StyleTextProp9Atom;
30
import org.apache.poi.hslf.record.StyleTextPropAtom;
31
import org.apache.poi.hslf.record.TextAutoNumberSchemeEnum;
32
import org.apache.poi.POIDataSamples;
33
34
35
/**
36
 * Test that checks numbered list functionality.
37
 * 
38
 * @author Alex Nikiforov [mailto:anikif@gmail.com]
39
 */
40
public final class TestNumberedList extends TestCase {
41
    private static POIDataSamples _slTests = POIDataSamples.getSlideShowInstance();
42
43
	protected void setUp() throws Exception {
44
	}
45
46
	public void testNumberedList() throws Exception {
47
		SlideShow ppt = new SlideShow(_slTests.openResourceAsStream("numbers.ppt"));
48
		assertTrue("No Exceptions while reading file", true);
49
50
		final Slide[] slides = ppt.getSlides();
51
		assertEquals(2, slides.length);
52
		checkSlide0(slides[0]);
53
		checkSlide1(slides[1]);
54
	}
55
	private void checkSlide0(final Slide s) {
56
		final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();
57
		assertNotNull(numberedListArray);
58
		assertEquals(1, numberedListArray.length);//Just one text box here
59
		final StyleTextProp9Atom numberedListInfo = numberedListArray[0];
60
		assertNotNull(numberedListInfo);
61
		final TextPFException9[] autoNumbers = numberedListInfo.getAutoNumberTypes();
62
		assertNotNull(autoNumbers);
63
		assertEquals(4, autoNumbers.length);
64
		assertTrue(4 == autoNumbers[0].getAutoNumberStartNumber());
65
		assertNull(autoNumbers[1].getAutoNumberStartNumber());
66
		assertTrue(3 == autoNumbers[2].getAutoNumberStartNumber());
67
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicPeriod == autoNumbers[0].getAutoNumberScheme());
68
		assertNull(autoNumbers[1].getAutoNumberScheme());
69
		assertTrue(TextAutoNumberSchemeEnum.ANM_AlphaLcParenRight == autoNumbers[2].getAutoNumberScheme());
70
			
71
		TextRun[] textRuns = s.getTextRuns();
72
		assertEquals(2, textRuns.length);
73
74
		RichTextRun textRun = textRuns[0].getRichTextRuns()[0];
75
		assertEquals("titTe", textRun.getRawText());
76
		assertEquals(1, textRuns[0].getRichTextRuns().length);
77
		assertFalse(textRun.isBullet());
78
79
		assertEquals("This is a text placeholder that \rfollows the design pattern\rJust a test\rWithout any paragraph\rSecond paragraph first line c) ;\rSecond paragraph second line d) . \r", textRuns[1].getRawText());
80
		
81
		final EscherTextboxWrapper[] styleAtoms = s.getTextboxWrappers();
82
		assertEquals(textRuns.length, styleAtoms.length);
83
		final EscherTextboxWrapper wrapper =  styleAtoms[1];
84
		final StyleTextPropAtom styleTextPropAtom = wrapper.getStyleTextPropAtom();
85
		final List<TextPropCollection> textProps = styleTextPropAtom.getCharacterStyles();
86
		final TextPropCollection[] props = (TextPropCollection[]) textProps.toArray(new TextPropCollection[textProps.size()]);
87
		assertEquals(60, props[0].getCharactersCovered());
88
		assertEquals(34, props[1].getCharactersCovered());
89
		assertEquals(68, props[2].getCharactersCovered());
90
	}
91
	private void checkSlide1(final Slide s) {
92
		final StyleTextProp9Atom[] numberedListArray = s.getNumberedListInfo();
93
		assertNotNull(numberedListArray);
94
		assertEquals(1, numberedListArray.length);//Just one text box here
95
		final StyleTextProp9Atom numberedListInfo = numberedListArray[0];
96
		assertNotNull(numberedListInfo);
97
		final TextPFException9[] autoNumbers = numberedListInfo.getAutoNumberTypes();
98
		assertNotNull(autoNumbers);
99
		assertEquals(4, autoNumbers.length);
100
		assertTrue(9 == autoNumbers[0].getAutoNumberStartNumber());
101
		assertNull(autoNumbers[1].getAutoNumberStartNumber());
102
		assertTrue(3 == autoNumbers[2].getAutoNumberStartNumber());
103
		assertTrue(TextAutoNumberSchemeEnum.ANM_ArabicParenRight == autoNumbers[0].getAutoNumberScheme());
104
		assertNull(autoNumbers[1].getAutoNumberScheme());
105
		assertTrue(TextAutoNumberSchemeEnum.ANM_AlphaUcPeriod == autoNumbers[2].getAutoNumberScheme());
106
107
		final TextRun[] textRuns = s.getTextRuns();
108
		assertEquals(2, textRuns.length);
109
110
		RichTextRun textRun = textRuns[0].getRichTextRuns()[0];
111
		assertEquals("Second Slide Title", textRun.getRawText());
112
		assertEquals(1, textRuns[0].getRichTextRuns().length);
113
		assertFalse(textRun.isBullet());
114
115
		assertEquals("This is a text placeholder that \rfollows the design pattern\rJust a test\rWithout any paragraph\rSecond paragraph first line c) ;\rSecond paragraph second line d) . \r", textRuns[1].getRawText());
116
		
117
		final EscherTextboxWrapper[] styleAtoms = s.getTextboxWrappers();
118
		assertEquals(textRuns.length, styleAtoms.length);
119
		final EscherTextboxWrapper wrapper =  styleAtoms[1];
120
		final StyleTextPropAtom styleTextPropAtom = wrapper.getStyleTextPropAtom();
121
		final List<TextPropCollection> textProps = styleTextPropAtom.getCharacterStyles();
122
		
123
		final TextPropCollection[] props = (TextPropCollection[]) textProps.toArray(new TextPropCollection[textProps.size()]);
124
		assertEquals(33, props[0].getCharactersCovered());
125
		assertEquals(61, props[1].getCharactersCovered());
126
		assertEquals(68, props[2].getCharactersCovered());
127
	}
128
}

Return to bug 53979