OpenConcerto

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

svn://code.openconcerto.org/openconcerto

Rev

Rev 17 | Rev 41 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
17 ilm 1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 OpenConcerto, by ILM Informatique. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of the GNU General Public License Version 3
7
 * only ("GPL"). You may not use this file except in compliance with the License. You can obtain a
8
 * copy of the License at http://www.gnu.org/licenses/gpl-3.0.html See the License for the specific
9
 * language governing permissions and limitations under the License.
10
 *
11
 * When distributing the software, include this License Header Notice in each file.
12
 */
13
 
14
 /*
15
 * Row created on 10 décembre 2005
16
 */
17
package org.openconcerto.openoffice.spreadsheet;
18
 
25 ilm 19
import org.openconcerto.openoffice.ODDocument;
20
import org.openconcerto.openoffice.StyleDesc;
21
import org.openconcerto.openoffice.StyleProperties;
22
import org.openconcerto.openoffice.StyleStyleDesc;
17 ilm 23
import org.openconcerto.openoffice.XMLVersion;
24
 
25 ilm 25
import java.util.Arrays;
17 ilm 26
import java.util.List;
27
 
28
import org.jdom.Element;
29
 
30
/**
31
 * A row in a Calc document. This class will only break "repeated" attributes on demand (eg for
32
 * setting a value).
33
 *
34
 * @author Sylvain
35
 * @param <D> type of document
36
 */
37
public class Row<D extends ODDocument> extends TableCalcNode<RowStyle, D> {
38
 
39
    static Element createEmpty(XMLVersion ns) {
40
        return new Element("table-row", ns.getTABLE());
41
    }
42
 
43
    private final Table<D> parent;
44
    private final int index;
25 ilm 45
    private int repeated;
17 ilm 46
    // the same immutable cell instance is repeated, but each MutableCell is only once
47
    // ATTN MutableCell have their index as attribute
25 ilm 48
    // array is faster than List
49
    private Cell<D>[] cells;
50
    private int cellCount;
17 ilm 51
 
25 ilm 52
    Row(Table<D> parent, Element tableRowElem, int index, StyleDesc<RowStyle> styleDesc, StyleDesc<CellStyle> cellStyleDesc) {
53
        super(parent.getODDocument(), tableRowElem, styleDesc);
17 ilm 54
        this.parent = parent;
55
        this.index = index;
25 ilm 56
        this.repeated = Axis.ROW.getRepeated(getElement());
57
        @SuppressWarnings("unchecked")
58
        final Cell<D>[] unsafe = new Cell[parent.getColumnCount()];
59
        this.cells = unsafe;
60
        this.cellCount = 0;
17 ilm 61
        for (final Element cellElem : this.getCellElements()) {
25 ilm 62
            addCellElem(cellElem, cellStyleDesc);
17 ilm 63
        }
64
    }
65
 
25 ilm 66
    private final void ensureRoom(int additionalItems) {
67
        final int requiredSize = this.getCellCount() + additionalItems;
68
        if (requiredSize > this.cells.length) {
69
            this.cells = Arrays.copyOf(this.cells, requiredSize);
70
        }
71
    }
72
 
17 ilm 73
    protected final Table<D> getSheet() {
74
        return this.parent;
75
    }
76
 
25 ilm 77
    // ATTN index of the first row
17 ilm 78
    final int getY() {
79
        return this.index;
80
    }
81
 
25 ilm 82
    // inclusive
83
    final int getLastY() {
84
        return this.getY() + this.getRepeated() - 1;
85
    }
86
 
87
    final int getRepeated() {
88
        return this.repeated;
89
    }
90
 
91
    final void setRepeated(int newRepeated) {
92
        Axis.ROW.setRepeated(getElement(), newRepeated);
93
        this.repeated = newRepeated;
94
    }
95
 
17 ilm 96
    // plain Cell instances have multiple indexes (if repeated) but MutableCell are unique
97
    final int getX(MutableCell<D> c) {
25 ilm 98
        final int stop = this.getCellCount();
99
        for (int i = 0; i < stop; i++) {
100
            final Cell<D> item = this.cells[i];
101
            if (c.equals(item))
102
                return i;
103
        }
104
        return -1;
17 ilm 105
    }
106
 
25 ilm 107
    private void addCellElem(final Element cellElem, StyleDesc<CellStyle> cellStyleDesc) {
108
        final Cell<D> cell = new Cell<D>(this, cellElem, cellStyleDesc);
109
        final String repeatedS = cellElem.getAttributeValue("number-columns-repeated", this.getTABLE());
110
        final int toRepeat = StyleProperties.parseInt(repeatedS, 1);
111
        final int stop = this.cellCount + toRepeat;
112
        for (int i = this.cellCount; i < stop; i++) {
113
            this.cells[i] = cell;
17 ilm 114
        }
25 ilm 115
        this.cellCount = stop;
17 ilm 116
    }
117
 
118
    /**
119
     * All cells of this row.
120
     *
121
     * @return cells of this row, only "table-cell" and "covered-table-cell".
122
     */
123
    @SuppressWarnings("unchecked")
124
    private List<Element> getCellElements() {
125
        // seuls table-cell et covered-table-cell sont légaux
126
        return this.getElement().getChildren();
127
    }
128
 
25 ilm 129
    protected final int getCellCount() {
130
        return this.cellCount;
131
    }
132
 
133
    private final List<Cell<D>> getCellsAsList() {
134
        return Arrays.asList(this.cells);
135
    }
136
 
17 ilm 137
    protected final Cell<D> getCellAt(int col) {
25 ilm 138
        return this.cells[col];
17 ilm 139
    }
140
 
141
    protected final Cell<D> getValidCellAt(int col) {
142
        final Cell<D> c = this.getCellAt(col);
143
        if (!c.isValid())
144
            throw new IllegalArgumentException("invalid cell " + c);
145
        return c;
146
    }
147
 
148
    public final MutableCell<D> getMutableCellAt(final int col) {
25 ilm 149
        final Cell<D> c = this.getValidCellAt(col);
17 ilm 150
        if (!(c instanceof MutableCell)) {
25 ilm 151
            RepeatedBreaker.<D> getCellBreaker().breakRepeated(this, getCellsAsList(), col);
17 ilm 152
        }
153
        return (MutableCell<D>) this.getValidCellAt(col);
154
    }
155
 
156
    // rempli cette ligne avec autant de cellules vides qu'il faut
25 ilm 157
    void columnCountChanged(StyleStyleDesc<CellStyle> cellStyleDesc) {
158
        final int diff = this.getSheet().getColumnCount() - getCellCount();
17 ilm 159
        if (diff < 0) {
160
            throw new IllegalStateException("should have used Table.removeColumn()");
161
        } else if (diff > 0) {
162
            final Element e = Cell.createEmpty(this.getSheet().getODDocument().getVersion(), diff);
163
            this.getElement().addContent(e);
25 ilm 164
            this.ensureRoom(diff);
165
            addCellElem(e, cellStyleDesc);
17 ilm 166
        }
25 ilm 167
        assert this.getCellCount() == this.getSheet().getColumnCount();
17 ilm 168
    }
169
 
170
    void checkRemove(int firstIndex, int lastIndexExcl) {
25 ilm 171
        if (lastIndexExcl > getCellCount()) {
172
            throw new IndexOutOfBoundsException(lastIndexExcl + " > " + getCellCount());
17 ilm 173
        }
174
        if (!this.getCellAt(firstIndex).isValid())
175
            throw new IllegalArgumentException("unable to remove covered cell at " + firstIndex);
176
    }
177
 
25 ilm 178
    // ATTN unsafe, must call checkRemove() first
17 ilm 179
    void removeCells(int firstIndex, int lastIndexExcl) {
180
        this.getMutableCellAt(firstIndex).unmerge();
181
 
182
        // if lastIndex == size, nothing to do
25 ilm 183
        if (lastIndexExcl < getCellCount()) {
17 ilm 184
            if (!this.getCellAt(lastIndexExcl - 1).isValid()) {
185
                int currentCol = lastIndexExcl - 2;
186
                // the covering cell is on this row since last cells of previous rows have been
187
                // unmerged (see *)
188
                // we've just unmerged firstIndex so there must be a non covered cell before it
189
                while (!this.getCellAt(currentCol).isValid())
190
                    currentCol--;
191
                this.getMutableCellAt(currentCol).unmerge();
192
            }
193
            // * lastIndex-1 is now uncovered, we can now unmerge it to assure our following rows
194
            // that any covered cell they encounter is on them and not above
195
            // plus of course if the last cell removed is covering following columns
196
            this.getMutableCellAt(lastIndexExcl - 1).unmerge();
197
        }
198
 
199
        for (int i = firstIndex; i < lastIndexExcl; i++) {
200
            // ok to detach multiple times the same element (since repeated cells share the same XML
201
            // element)
25 ilm 202
            this.cells[firstIndex].getElement().detach();
17 ilm 203
        }
25 ilm 204
        final int movedCount = getCellCount() - lastIndexExcl;
205
        System.arraycopy(this.cells, lastIndexExcl, this.cells, firstIndex, movedCount);
206
        this.cells = Arrays.copyOfRange(this.cells, 0, firstIndex + movedCount);
207
        this.cellCount = this.cells.length;
208
        assert this.getCellCount() == this.getSheet().getColumnCount();
17 ilm 209
    }
210
 
211
}