OpenConcerto

Dépôt officiel du code source de l'ERP OpenConcerto
sonarqube

svn://code.openconcerto.org/openconcerto

Rev

Rev 21 | Rev 41 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 21 Rev 25
Line 14... Line 14...
14
 package org.openconcerto.openoffice.spreadsheet;
14
 package org.openconcerto.openoffice.spreadsheet;
15
 
15
 
16
import org.openconcerto.openoffice.LengthUnit;
16
import org.openconcerto.openoffice.LengthUnit;
17
import org.openconcerto.openoffice.ODDocument;
17
import org.openconcerto.openoffice.ODDocument;
18
import org.openconcerto.openoffice.Style;
18
import org.openconcerto.openoffice.Style;
-
 
19
import org.openconcerto.openoffice.StyleDesc;
19
import org.openconcerto.openoffice.StyleStyleDesc;
20
import org.openconcerto.openoffice.StyleStyleDesc;
20
import org.openconcerto.openoffice.XMLVersion;
21
import org.openconcerto.openoffice.XMLVersion;
21
import org.openconcerto.openoffice.spreadsheet.SheetTableModel.MutableTableModel;
22
import org.openconcerto.openoffice.spreadsheet.SheetTableModel.MutableTableModel;
22
import org.openconcerto.utils.CollectionUtils;
23
import org.openconcerto.utils.CollectionUtils;
23
import org.openconcerto.utils.Tuple2;
24
import org.openconcerto.utils.Tuple2;
Line 28... Line 29...
28
import java.math.BigDecimal;
29
import java.math.BigDecimal;
29
import java.util.ArrayList;
30
import java.util.ArrayList;
30
import java.util.HashMap;
31
import java.util.HashMap;
31
import java.util.HashSet;
32
import java.util.HashSet;
32
import java.util.List;
33
import java.util.List;
33
import java.util.ListIterator;
-
 
34
import java.util.Map;
34
import java.util.Map;
35
import java.util.Set;
35
import java.util.Set;
36
import java.util.regex.Matcher;
36
import java.util.regex.Matcher;
37
 
37
 
38
import javax.swing.table.TableModel;
38
import javax.swing.table.TableModel;
Line 58... Line 58...
58
    static final String getName(final Element elem) {
58
    static final String getName(final Element elem) {
59
        return elem.getAttributeValue("name", elem.getNamespace("table"));
59
        return elem.getAttributeValue("name", elem.getNamespace("table"));
60
    }
60
    }
61
 
61
 
62
    // ATTN Row have their index as attribute
62
    // ATTN Row have their index as attribute
63
    private final List<Row<D>> rows;
63
    private final ArrayList<Row<D>> rows;
64
    private int headerRowCount;
64
    private TableGroup rowGroup;
65
    private final List<Column<D>> cols;
65
    private final ArrayList<Column<D>> cols;
66
    private int headerColumnCount;
66
    private TableGroup columnGroup;
67
 
67
 
68
    public Table(D parent, Element local) {
68
    public Table(D parent, Element local) {
69
        super(parent, local, TableStyle.class);
69
        super(parent, local, TableStyle.class);
70
 
70
 
71
        this.rows = new ArrayList<Row<D>>();
71
        this.rows = new ArrayList<Row<D>>(64);
72
        this.cols = new ArrayList<Column<D>>();
72
        this.cols = new ArrayList<Column<D>>(32);
73
 
73
 
-
 
74
        // read columns first since Row constructor needs it
74
        this.readColumns();
75
        this.readColumns();
75
        this.readRows();
76
        this.readRows();
76
    }
77
    }
77
 
78
 
78
    private void readColumns() {
79
    private void readColumns() {
79
        this.read(true);
80
        this.read(Axis.COLUMN);
80
    }
81
    }
81
 
82
 
82
    private final void readRows() {
83
    private final void readRows() {
83
        this.read(false);
84
        this.read(Axis.ROW);
84
    }
85
    }
85
 
86
 
86
    private final void read(final boolean col) {
87
    private final void read(final Axis axis) {
-
 
88
        final boolean col = axis == Axis.COLUMN;
87
        final Tuple2<List<Element>, Integer> r = flatten(col);
89
        final Tuple2<TableGroup, List<Element>> r = TableGroup.createRoot(this, axis);
88
        (col ? this.cols : this.rows).clear();
90
        final ArrayList<?> l = col ? this.cols : this.rows;
89
        for (final Element clone : r.get0()) {
91
        final int oldSize = l.size();
-
 
92
        l.clear();
-
 
93
        final int newSize = r.get0().getSize();
-
 
94
        l.ensureCapacity(newSize);
90
            if (col)
95
        if (col) {
-
 
96
            final StyleStyleDesc<ColumnStyle> colStyleDesc = getColumnStyleDesc();
-
 
97
            for (final Element clone : r.get1())
91
                this.addCol(clone);
98
                this.addCol(clone, colStyleDesc);
-
 
99
            this.columnGroup = r.get0();
92
            else
100
        } else {
-
 
101
            final StyleStyleDesc<RowStyle> rowStyleDesc = getRowStyleDesc();
-
 
102
            final StyleStyleDesc<CellStyle> cellStyleDesc = getCellStyleDesc();
-
 
103
            for (final Element clone : r.get1())
-
 
104
                this.addRow(clone, rowStyleDesc, cellStyleDesc);
93
                this.addRow(clone);
105
            this.rowGroup = r.get0();
94
        }
106
        }
95
        if (col)
-
 
96
            this.headerColumnCount = r.get1();
107
        // this always copy the array, so make sure we reclaim enough memory (~ 64k)
97
        else
108
        if (oldSize - newSize > 8192) {
98
            this.headerRowCount = r.get1();
109
            l.trimToSize();
99
    }
110
        }
100
 
-
 
101
    private final void addCol(Element clone) {
-
 
102
        this.cols.add(new Column<D>(this, clone));
111
        assert newSize == (col ? this.getColumnCount() : this.getRowCount());
103
    }
112
    }
104
 
113
 
105
    private Tuple2<List<Element>, Integer> flatten(boolean col) {
114
    private final void addCol(Element clone, StyleStyleDesc<ColumnStyle> colStyleDesc) {
106
        final List<Element> res = new ArrayList<Element>();
115
        this.cols.add(new Column<D>(this, clone, colStyleDesc));
107
        final Element header = this.getElement().getChild("table-header-" + getName(col) + "s", getTABLE());
-
 
108
        if (header != null)
116
    }
109
            res.addAll(flatten(header, col));
-
 
110
        final int headerCount = res.size();
-
 
111
 
117
 
-
 
118
    static final int flattenChildren(final List<Element> res, final Element elem, final Axis axis) {
-
 
119
        int count = 0;
-
 
120
        // array so that flatten1() can modify an int
-
 
121
        int[] index = new int[] { 0 };
-
 
122
        // copy since we will change our children (don't use List.listIterator(int) since it
-
 
123
        // re-filters all content)
-
 
124
        @SuppressWarnings("unchecked")
-
 
125
        final List<Element> children = new ArrayList<Element>(elem.getChildren(axis.getElemName(), elem.getNamespace()));
-
 
126
        final int stop = children.size();
-
 
127
        for (int i = 0; i < stop; i++) {
-
 
128
            final Element row = children.get(i);
112
        res.addAll(flatten(getElement(), col));
129
            count += flatten1(res, row, axis, index);
-
 
130
        }
-
 
131
        return count;
-
 
132
    }
113
 
133
 
-
 
134
    static int flatten1(final List<Element> res, final Element row, final Axis axis) {
114
        return Tuple2.create(res, headerCount);
135
        return flatten1(res, row, axis, null);
115
    }
136
    }
116
 
137
 
117
    @SuppressWarnings("unchecked")
138
    // add XML elements to res and return the logical count
118
    private List<Element> flatten(final Element elem, boolean col) {
139
    private static int flatten1(final List<Element> res, final Element row, final Axis axis, final int[] parentIndex) {
119
        final String childName = getName(col);
140
        final int resSize = res.size();
120
        final List<Element> children = elem.getChildren("table-" + childName, getTABLE());
-
 
121
        // not final, since iter.add() does not work consistently, and
-
 
122
        // thus we must recreate an iterator each time
-
 
123
        ListIterator<Element> iter = children.listIterator();
141
        final Attribute repeatedAttr = axis.getRepeatedAttr(row);
124
        while (iter.hasNext()) {
-
 
125
            final Element row = iter.next();
-
 
126
            final Attribute repeatedAttr = row.getAttribute("number-" + childName + "s-repeated", getTABLE());
142
        final int repeated = repeatedAttr == null ? 1 : Integer.parseInt(repeatedAttr.getValue());
127
            if (repeatedAttr != null) {
143
        if (axis == Axis.COLUMN && repeated > 1) {
128
                row.removeAttribute(repeatedAttr);
144
            row.removeAttribute(repeatedAttr);
129
                final int index = iter.previousIndex();
145
            final Element parent = row.getParentElement();
130
                int repeated = Integer.parseInt(repeatedAttr.getValue());
146
            final int index = (parentIndex == null ? parent.indexOf(row) : parentIndex[0]) + 1;
131
                if (repeated > 60000) {
-
 
132
                    repeated = 10;
147
            res.add(row);
133
                }
-
 
134
                // -1 : we keep the original row
148
            // -1 : we keep the original row
135
                for (int i = 0; i < repeated - 1; i++) {
149
            for (int i = 0; i < repeated - 1; i++) {
136
                    final Element clone = (Element) row.clone();
150
                final Element clone = (Element) row.clone();
137
                    // cannot use iter.add() since on JDOM 1.1 if row is the last table-column
-
 
138
                    // before table-row the clone is added at the very end
-
 
139
                    children.add(index, clone);
151
                res.add(clone);
140
                }
-
 
141
                // restart after the added rows
-
 
142
                iter = children.listIterator(index + repeated);
152
                parent.addContent(index + i, clone);
143
            }
153
            }
-
 
154
        } else {
-
 
155
            res.add(row);
144
        }
156
        }
145
 
-
 
-
 
157
        if (parentIndex != null)
-
 
158
            parentIndex[0] += res.size() - resSize;
146
        return children;
159
        return repeated;
147
    }
160
    }
148
 
161
 
149
    public final String getName() {
162
    public final String getName() {
150
        return getName(this.getElement());
163
        return getName(this.getElement());
151
    }
164
    }
Line 156... Line 169...
156
 
169
 
157
    public void detach() {
170
    public void detach() {
158
        this.getElement().detach();
171
        this.getElement().detach();
159
    }
172
    }
160
 
173
 
161
    private final String getName(boolean col) {
-
 
162
        return col ? "column" : "row";
-
 
163
    }
-
 
164
 
-
 
165
    public final Object getPrintRanges() {
174
    public final Object getPrintRanges() {
166
        return this.getElement().getAttributeValue("print-ranges", this.getTABLE());
175
        return this.getElement().getAttributeValue("print-ranges", this.getTABLE());
167
    }
176
    }
168
 
177
 
169
    public final void setPrintRanges(String s) {
178
    public final void setPrintRanges(String s) {
Line 233... Line 242...
233
            x++;
242
            x++;
234
        }
243
        }
235
 
244
 
236
        // clone xml elements and add them to our tree
245
        // clone xml elements and add them to our tree
237
        final List<Element> clones = new ArrayList<Element>(count * copies);
246
        final List<Element> clones = new ArrayList<Element>(count * copies);
238
        for (int i = 0; i < copies; i++) {
247
        for (int l = start; l < stop;) {
-
 
248
            final Row<D> immutableRow = this.getRow(l);
-
 
249
            final Row<D> toClone;
-
 
250
            // MAYBE use something else than getMutableRow() since we don't need a single row.
-
 
251
            // the repeated row starts before the copied range, split it at the beginning
-
 
252
            if (immutableRow.getY() < l) {
-
 
253
                toClone = this.getMutableRow(l);
-
 
254
            } else {
-
 
255
                assert immutableRow.getY() == l;
-
 
256
                if (immutableRow.getLastY() >= stop) {
-
 
257
                    // the repeated row goes beyond the copied range, split it at the end
-
 
258
                    assert this.getRow(stop) == immutableRow;
-
 
259
                    this.getMutableRow(stop);
-
 
260
                    toClone = this.getRow(l);
-
 
261
                } else {
-
 
262
                    toClone = immutableRow;
-
 
263
                }
-
 
264
            }
-
 
265
            assert toClone.getY() == l;
-
 
266
            assert toClone.getLastY() < stop : "Row goes to far";
-
 
267
            l += toClone.getRepeated();
-
 
268
            clones.add((Element) toClone.getElement().clone());
-
 
269
        }
-
 
270
        final int clonesSize = clones.size();
239
            for (int l = start; l < stop; l++) {
271
        for (int i = 1; i < copies; i++) {
240
                final Element r = this.rows.get(l).getElement();
272
            for (int j = 0; j < clonesSize; j++) {
241
                clones.add((Element) r.clone());
273
                clones.add((Element) clones.get(j).clone());
242
            }
274
            }
243
        }
275
        }
244
        // works anywhere its XML element is
276
        // works anywhere its XML element is
-
 
277
        assert this.getRow(stop - 1).getLastY() == stop - 1 : "Adding XML element too far";
245
        JDOMUtils.insertAfter(this.rows.get(stop - 1).getElement(), clones);
278
        JDOMUtils.insertAfter(this.getRow(stop - 1).getElement(), clones);
246
 
279
 
247
        for (final Point coverOrigin : coverOriginsToUpdate) {
280
        for (final Point coverOrigin : coverOriginsToUpdate) {
248
            final MutableCell<D> coveringCell = getCellAt(coverOrigin);
281
            final MutableCell<D> coveringCell = getCellAt(coverOrigin);
249
            coveringCell.setRowsSpanned(coveringCell.getRowsSpanned() + count * copies);
282
            coveringCell.setRowsSpanned(coveringCell.getRowsSpanned() + count * copies);
250
        }
283
        }
251
 
284
 
252
        // synchronize our rows with our new tree
285
        // synchronize our rows with our new tree (rows' index have changed)
253
        this.readRows();
286
        this.readRows();
254
 
287
 
255
        // 19.627 in OpenDocument-v1.2-cs01-part1 : The table:end-cell-address attribute specifies
288
        // 19.627 in OpenDocument-v1.2-cs01-part1 : The table:end-cell-address attribute specifies
256
        // end position of the shape if it is included in a spreadsheet document.
289
        // end position of the shape if it is included in a spreadsheet document.
257
        if (updateCellAddresses && getODDocument() instanceof SpreadSheet) {
290
        if (updateCellAddresses && getODDocument() instanceof SpreadSheet) {
Line 321... Line 354...
321
                }
354
                }
322
            }
355
            }
323
        }
356
        }
324
    }
357
    }
325
 
358
 
326
    private synchronized void addRow(Element child) {
359
    private synchronized void addRow(Element child, StyleDesc<RowStyle> styleDesc, StyleDesc<CellStyle> cellStyleDesc) {
327
        this.rows.add(new Row<D>(this, child, this.rows.size()));
360
        final Row<D> row = new Row<D>(this, child, this.rows.size(), styleDesc, cellStyleDesc);
-
 
361
        final int toRepeat = row.getRepeated();
-
 
362
        for (int i = 0; i < toRepeat; i++) {
-
 
363
            this.rows.add(row);
-
 
364
        }
328
    }
365
    }
329
 
366
 
330
    public final Point resolveHint(String ref) {
367
    public final Point resolveHint(String ref) {
331
        final Point res = resolve(ref);
368
        final Point res = resolve(ref);
332
        if (res != null) {
369
        if (res != null) {
Line 344... Line 381...
344
            return false;
381
            return false;
345
        else
382
        else
346
            return this.getImmutableCellAt(x, y).isValid();
383
            return this.getImmutableCellAt(x, y).isValid();
347
    }
384
    }
348
 
385
 
-
 
386
    /**
-
 
387
     * Return a modifiable cell at the passed coordinates. This is slower than
-
 
388
     * {@link #getImmutableCellAt(int, int)} since this method may modify the underlying XML (e.g.
-
 
389
     * break up repeated cells to allow for modification of only the returned cell).
-
 
390
     * 
-
 
391
     * @param x the column.
-
 
392
     * @param y the row.
-
 
393
     * @return the cell.
-
 
394
     * @see #getImmutableCellAt(int, int)
-
 
395
     */
349
    public final MutableCell<D> getCellAt(int x, int y) {
396
    public final MutableCell<D> getCellAt(int x, int y) {
350
        return this.getRow(y).getMutableCellAt(x);
397
        return this.getMutableRow(y).getMutableCellAt(x);
351
    }
398
    }
352
 
399
 
353
    public final MutableCell<D> getCellAt(String ref) {
400
    public final MutableCell<D> getCellAt(String ref) {
354
        return this.getCellAt(resolveHint(ref));
401
        return this.getCellAt(resolveHint(ref));
355
    }
402
    }
Line 373... Line 420...
373
            this.getCellAt(x, y).setValue(val);
420
            this.getCellAt(x, y).setValue(val);
374
    }
421
    }
375
 
422
 
376
    // *** get cell
423
    // *** get cell
377
 
424
 
-
 
425
    /**
-
 
426
     * Return a non modifiable cell at the passed coordinates. This is faster than
-
 
427
     * {@link #getCellAt(int, int)} since this method never modifies the underlying XML.
-
 
428
     * 
-
 
429
     * @param x the column.
-
 
430
     * @param y the row.
-
 
431
     * @return the cell.
-
 
432
     * @see #getCellAt(int, int)
-
 
433
     */
378
    protected final Cell<D> getImmutableCellAt(int x, int y) {
434
    public final Cell<D> getImmutableCellAt(int x, int y) {
379
        return this.getRow(y).getCellAt(x);
435
        return this.getRow(y).getCellAt(x);
380
    }
436
    }
381
 
437
 
382
    protected final Cell<D> getImmutableCellAt(String ref) {
438
    public final Cell<D> getImmutableCellAt(String ref) {
383
        final Point p = resolveHint(ref);
439
        final Point p = resolveHint(ref);
384
        return this.getImmutableCellAt(p.x, p.y);
440
        return this.getImmutableCellAt(p.x, p.y);
385
    }
441
    }
386
 
442
 
387
    /**
443
    /**
Line 455... Line 511...
455
        // and finally the column
511
        // and finally the column
456
        return this.getColumn(column).getElement().getAttributeValue("default-cell-style-name", getTABLE());
512
        return this.getColumn(column).getElement().getAttributeValue("default-cell-style-name", getTABLE());
457
    }
513
    }
458
 
514
 
459
    public final CellStyle getStyleAt(int column, int row) {
515
    public final CellStyle getStyleAt(int column, int row) {
460
        return getCellStyleDesc().findStyle(this.getODDocument().getPackage(), this.getElement().getDocument(), this.getStyleNameAt(column, row));
516
        return getCellStyleDesc().findStyleForNode(this.getImmutableCellAt(column, row), this.getStyleNameAt(column, row));
461
    }
517
    }
462
 
518
 
463
    protected StyleStyleDesc<CellStyle> getCellStyleDesc() {
519
    protected StyleStyleDesc<CellStyle> getCellStyleDesc() {
464
        return Style.getStyleStyleDesc(CellStyle.class, getODDocument().getVersion());
520
        return Style.getStyleStyleDesc(CellStyle.class, getODDocument().getVersion());
465
    }
521
    }
Line 504... Line 560...
504
            }
560
            }
505
        }
561
        }
506
        return res;
562
        return res;
507
    }
563
    }
508
 
564
 
-
 
565
    protected final StyleStyleDesc<ColumnStyle> getColumnStyleDesc() {
-
 
566
        return Style.getStyleStyleDesc(ColumnStyle.class, XMLVersion.getVersion(getElement()));
-
 
567
    }
-
 
568
 
-
 
569
    protected final StyleStyleDesc<RowStyle> getRowStyleDesc() {
-
 
570
        return Style.getStyleStyleDesc(RowStyle.class, XMLVersion.getVersion(getElement()));
-
 
571
    }
-
 
572
 
509
    /**
573
    /**
510
     * Retourne la valeur de la cellule spécifiée.
574
     * Retourne la valeur de la cellule spécifiée.
511
     * 
575
     * 
512
     * @param ref une référence de la forme "A3".
576
     * @param ref une référence de la forme "A3".
513
     * @return la valeur de la cellule spécifiée.
577
     * @return la valeur de la cellule spécifiée.
Line 516... Line 580...
516
        return this.getImmutableCellAt(ref).getValue();
580
        return this.getImmutableCellAt(ref).getValue();
517
    }
581
    }
518
 
582
 
519
    // *** get count
583
    // *** get count
520
 
584
 
521
    private Row<D> getRow(int index) {
585
    final Row<D> getRow(int index) {
522
        return this.rows.get(index);
586
        return this.rows.get(index);
523
    }
587
    }
524
 
588
 
-
 
589
    final Row<D> getMutableRow(int y) {
-
 
590
        final Row<D> c = this.getRow(y);
-
 
591
        if (c.getRepeated() > 1) {
-
 
592
            RepeatedBreaker.<D> getRowBreaker().breakRepeated(this, this.rows, y);
-
 
593
            return this.getRow(y);
-
 
594
        } else {
-
 
595
            return c;
-
 
596
        }
-
 
597
    }
-
 
598
 
525
    public final Column<D> getColumn(int i) {
599
    public final Column<D> getColumn(int i) {
526
        return this.cols.get(i);
600
        return this.cols.get(i);
527
    }
601
    }
528
 
602
 
529
    public final int getRowCount() {
603
    public final int getRowCount() {
530
        return this.rows.size();
604
        return this.rows.size();
531
    }
605
    }
532
 
606
 
-
 
607
    public final TableGroup getRowGroup() {
-
 
608
        return this.rowGroup;
-
 
609
    }
-
 
610
 
-
 
611
    /**
-
 
612
     * Return the deepest group at the passed row.
-
 
613
     * 
-
 
614
     * @param y a row index.
-
 
615
     * @return the group at the index, never <code>null</code>.
-
 
616
     */
-
 
617
    public final TableGroup getRowGroupAt(final int y) {
-
 
618
        return this.getRowGroup().getDescendentOrSelfContaining(y);
-
 
619
    }
-
 
620
 
533
    public final int getHeaderRowCount() {
621
    public final int getHeaderRowCount() {
534
        return this.headerRowCount;
622
        return this.getRowGroup().getFollowingHeaderCount();
535
    }
623
    }
536
 
624
 
537
    public final int getColumnCount() {
625
    public final int getColumnCount() {
538
        return this.cols.size();
626
        return this.cols.size();
539
    }
627
    }
540
 
628
 
-
 
629
    public final TableGroup getColumnGroup() {
-
 
630
        return this.columnGroup;
-
 
631
    }
-
 
632
 
-
 
633
    /**
-
 
634
     * Return the deepest group at the passed column.
-
 
635
     * 
-
 
636
     * @param x a column index.
-
 
637
     * @return the group at the index, never <code>null</code>.
-
 
638
     */
-
 
639
    public final TableGroup getColumnGroupAt(final int x) {
-
 
640
        return this.getColumnGroup().getDescendentOrSelfContaining(x);
-
 
641
    }
-
 
642
 
541
    public final int getHeaderColumnCount() {
643
    public final int getHeaderColumnCount() {
542
        return this.headerColumnCount;
644
        return this.getColumnGroup().getFollowingHeaderCount();
543
    }
645
    }
544
 
646
 
545
    // *** set count
647
    // *** set count
546
 
648
 
547
    /**
649
    /**
Line 593... Line 695...
593
            if (colIndex < 0) {
695
            if (colIndex < 0) {
594
                elemToClone = Column.createEmpty(getODDocument().getVersion(), this.createDefaultColStyle());
696
                elemToClone = Column.createEmpty(getODDocument().getVersion(), this.createDefaultColStyle());
595
            } else {
697
            } else {
596
                elemToClone = getColumn(colIndex).getElement();
698
                elemToClone = getColumn(colIndex).getElement();
597
            }
699
            }
-
 
700
            final StyleStyleDesc<ColumnStyle> columnStyleDesc = getColumnStyleDesc();
598
            for (int i = 0; i < toGrow; i++) {
701
            for (int i = 0; i < toGrow; i++) {
599
                final Element newElem = (Element) elemToClone.clone();
702
                final Element newElem = (Element) elemToClone.clone();
600
                this.getElement().addContent(indexOfLastCol + 1 + i, newElem);
703
                this.getElement().addContent(indexOfLastCol + 1 + i, newElem);
601
                this.cols.add(new Column<D>(this, newElem));
704
                this.cols.add(new Column<D>(this, newElem, columnStyleDesc));
602
            }
705
            }
603
            // now update widths
706
            // now update widths
604
            updateWidth(keepTableWidth);
707
            updateWidth(keepTableWidth);
605
 
708
 
606
            // add needed cells
709
            // add needed cells
-
 
710
            final StyleStyleDesc<CellStyle> cellStyleDesc = this.getCellStyleDesc();
-
 
711
            final int rowCount = this.getRowCount();
-
 
712
            for (int i = 0; i < rowCount;) {
607
            for (final Row r : this.rows) {
713
                final Row<D> r = this.getRow(i);
608
                r.columnCountChanged();
714
                r.columnCountChanged(cellStyleDesc);
-
 
715
                i += r.getRepeated();
609
            }
716
            }
610
        }
717
        }
611
    }
718
    }
612
 
719
 
613
    public final void removeColumn(int colIndex, final boolean keepTableWidth) {
720
    public final void removeColumn(int colIndex, final boolean keepTableWidth) {
Line 627... Line 734...
627
     * @param keepTableWidth <code>true</code> if the table should be same width after the column
734
     * @param keepTableWidth <code>true</code> if the table should be same width after the column
628
     *        change.
735
     *        change.
629
     */
736
     */
630
    public final void removeColumn(int firstIndex, int lastIndex, final boolean keepTableWidth) {
737
    public final void removeColumn(int firstIndex, int lastIndex, final boolean keepTableWidth) {
631
        // first check that removeCells() will succeed, so that we avoid an incoherent XML state
738
        // first check that removeCells() will succeed, so that we avoid an incoherent XML state
-
 
739
        final int rowCount = this.getRowCount();
-
 
740
        for (int i = 0; i < rowCount;) {
632
        for (final Row r : this.rows) {
741
            final Row<D> r = this.getRow(i);
633
            r.checkRemove(firstIndex, lastIndex);
742
            r.checkRemove(firstIndex, lastIndex);
-
 
743
            i += r.getRepeated();
634
        }
744
        }
635
        // rm column element
745
        // rm column element
636
        remove(true, firstIndex, lastIndex - 1);
746
        remove(Axis.COLUMN, firstIndex, lastIndex - 1);
637
        // update widths
747
        // update widths
638
        updateWidth(keepTableWidth);
748
        updateWidth(keepTableWidth);
639
        // rm cells
749
        // rm cells
-
 
750
        for (int i = 0; i < rowCount;) {
640
        for (final Row r : this.rows) {
751
            final Row<D> r = this.getRow(i);
641
            r.removeCells(firstIndex, lastIndex);
752
            r.removeCells(firstIndex, lastIndex);
-
 
753
            i += r.getRepeated();
642
        }
754
        }
643
    }
755
    }
644
 
756
 
645
    private void updateWidth(final boolean keepTableWidth) {
757
    private void updateWidth(final boolean keepTableWidth) {
646
        final Float currentWidth = getWidth();
758
        final Float currentWidth = getWidth();
Line 707... Line 819...
707
        final ColumnStyle colStyle = ColumnStyle.DESC.createAutoStyle(this.getODDocument().getPackage(), "defaultCol");
819
        final ColumnStyle colStyle = ColumnStyle.DESC.createAutoStyle(this.getODDocument().getPackage(), "defaultCol");
708
        colStyle.setWidth(20.0f);
820
        colStyle.setWidth(20.0f);
709
        return colStyle;
821
        return colStyle;
710
    }
822
    }
711
 
823
 
712
    private final void setCount(final boolean col, final int newSize) {
824
    private final void setCount(final Axis col, final int newSize) {
713
        this.remove(col, newSize, -1);
825
        this.remove(col, newSize, -1);
714
    }
826
    }
715
 
827
 
716
    // both inclusive
828
    // both inclusive
717
    private final void remove(final boolean col, final int fromIndex, final int toIndexIncl) {
829
    private final void remove(final Axis col, final int fromIndex, final int toIndexIncl) {
718
        // ok since rows and cols are flattened in ctor
830
        assert col == Axis.COLUMN || toIndexIncl < 0 : "Row index will be wrong";
719
        final List<? extends TableCalcNode> l = col ? this.cols : this.rows;
831
        final List<? extends TableCalcNode<?, ?>> l = col == Axis.COLUMN ? this.cols : this.rows;
720
        final int toIndexValid = CollectionUtils.getValidIndex(l, toIndexIncl);
832
        final int toIndexValid = CollectionUtils.getValidIndex(l, toIndexIncl);
721
        for (int i = toIndexValid; i >= fromIndex; i--) {
833
        final int toRemoveCount = toIndexValid - fromIndex + 1;
-
 
834
        int removedCount = 0;
-
 
835
        while (removedCount < toRemoveCount) {
722
            // works anywhere its XML element is
836
            // works backwards to keep y OK
-
 
837
            final int i = toIndexValid - removedCount;
-
 
838
            final TableCalcNode<?, ?> removed = l.get(i);
-
 
839
            if (removed instanceof Row) {
-
 
840
                final Row<?> r = (Row<?>) removed;
-
 
841
                final int removeFromRepeated = i - Math.max(fromIndex, r.getY()) + 1;
-
 
842
                // removedCount grows each iteration
-
 
843
                assert removeFromRepeated > 0;
-
 
844
                final int newRepeated = r.getRepeated() - removeFromRepeated;
-
 
845
                if (newRepeated == 0)
-
 
846
                    removed.getElement().detach();
-
 
847
                else
-
 
848
                    r.setRepeated(newRepeated);
-
 
849
                removedCount += removeFromRepeated;
-
 
850
            } else {
-
 
851
                // Columns are always flattened
723
            l.remove(i).getElement().detach();
852
                removed.getElement().detach();
-
 
853
                removedCount++;
-
 
854
            }
724
        }
855
        }
-
 
856
        // one remove to be efficient
-
 
857
        l.subList(fromIndex, toIndexValid + 1).clear();
725
    }
858
    }
726
 
859
 
727
    public final void ensureRowCount(int newSize) {
860
    public final void ensureRowCount(int newSize) {
728
        if (newSize > this.getRowCount())
861
        if (newSize > this.getRowCount())
729
            this.setRowCount(newSize);
862
            this.setRowCount(newSize);
Line 739... Line 872...
739
     * 
872
     * 
740
     * @param newSize the new row count.
873
     * @param newSize the new row count.
741
     * @param rowIndex the index of the row to be copied, -1 for empty row (i.e. default style).
874
     * @param rowIndex the index of the row to be copied, -1 for empty row (i.e. default style).
742
     */
875
     */
743
    public final void setRowCount(int newSize, int rowIndex) {
876
    public final void setRowCount(int newSize, int rowIndex) {
-
 
877
        final int toGrow = newSize - this.getRowCount();
-
 
878
        if (toGrow < 0) {
-
 
879
            setCount(Axis.ROW, newSize);
-
 
880
        } else if (toGrow > 0) {
744
        final Element elemToClone;
881
            final Element elemToClone;
745
        if (rowIndex < 0) {
882
            if (rowIndex < 0) {
746
            elemToClone = Row.createEmpty(this.getODDocument().getVersion());
883
                elemToClone = Row.createEmpty(this.getODDocument().getVersion());
747
            // each row MUST have the same number of columns
884
                // each row MUST have the same number of columns
748
            elemToClone.addContent(Cell.createEmpty(this.getODDocument().getVersion(), this.getColumnCount()));
885
                elemToClone.addContent(Cell.createEmpty(this.getODDocument().getVersion(), this.getColumnCount()));
749
        } else
-
 
750
            elemToClone = getRow(rowIndex).getElement();
-
 
751
        final int toGrow = newSize - this.getRowCount();
-
 
752
        if (toGrow < 0) {
-
 
753
            setCount(false, newSize);
-
 
754
        } else {
886
            } else {
755
            for (int i = 0; i < toGrow; i++) {
-
 
756
                final Element newElem = (Element) elemToClone.clone();
887
                elemToClone = (Element) getRow(rowIndex).getElement().clone();
757
                // as per section 8.1.1 rows are the last elements inside a table
-
 
758
                this.getElement().addContent(newElem);
-
 
759
                addRow(newElem);
-
 
760
            }
888
            }
-
 
889
            Axis.ROW.setRepeated(elemToClone, toGrow);
-
 
890
            // as per section 8.1.1 rows are the last elements inside a table
-
 
891
            this.getElement().addContent(elemToClone);
-
 
892
            addRow(elemToClone, getRowStyleDesc(), getCellStyleDesc());
761
        }
893
        }
762
    }
894
    }
763
 
895
 
764
    // *** table models
896
    // *** table models
765
 
897
 
Line 946... Line 1078...
946
        }
1078
        }
947
 
1079
 
948
        public final Range getCurrentRegion() {
1080
        public final Range getCurrentRegion() {
949
            while (this.checkFrame())
1081
            while (this.checkFrame())
950
                ;// bounded by table size
1082
                ;// bounded by table size
951
            return new Range(getName(), new Point(minX, minY), new Point(maxX, maxY));
1083
            return new Range(getName(), new Point(this.minX, this.minY), new Point(this.maxX, this.maxY));
952
        }
1084
        }
953
    }
1085
    }
954
 
1086
 
955
    public final Range getCurrentRegion(String ref) {
1087
    public final Range getCurrentRegion(String ref) {
956
        return this.getCurrentRegion(ref, false);
1088
        return this.getCurrentRegion(ref, false);
Line 966... Line 1098...
966
     * columns.
1098
     * columns.
967
     * 
1099
     * 
968
     * @param startX x coordinate.
1100
     * @param startX x coordinate.
969
     * @param startY y coordinate.
1101
     * @param startY y coordinate.
970
     * @return the smallest range containing the passed cell.
1102
     * @return the smallest range containing the passed cell.
971
     * @see http://msdn.microsoft.com/library/aa214248(v=office.11).aspx
1103
     * @see <a href="http://msdn.microsoft.com/library/aa214248(v=office.11).aspx">CurrentRegion
-
 
1104
     *      Property</a>
972
     */
1105
     */
973
    public final Range getCurrentRegion(final int startX, final int startY) {
1106
    public final Range getCurrentRegion(final int startX, final int startY) {
974
        return this.getCurrentRegion(startX, startY, false);
1107
        return this.getCurrentRegion(startX, startY, false);
975
    }
1108
    }
976
 
1109