1 /* This file is part of the KDE project
2    Copyright 2010 Marijn Kruisselbrink <mkruisselbrink@kde.org>
3 
4    This library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Library General Public
6    License as published by the Free Software Foundation; either
7    version 2 of the License, or (at your option) any later version.
8 
9    This library is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    Library General Public License for more details.
13 
14    You should have received a copy of the GNU Library General Public License
15    along with this library; see the file COPYING.LIB.  If not, write to
16    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17    Boston, MA 02110-1301, USA.
18 */
19 #include "RowRepeatStorage.h"
20 
21 #include <QList>
22 #include <QPair>
23 #include <QDebug>
24 
25 #include "calligra_sheets_limits.h"
26 
27 using namespace Calligra::Sheets;
28 
RowRepeatStorage()29 RowRepeatStorage::RowRepeatStorage()
30 {
31 }
32 
dump() const33 void RowRepeatStorage::dump() const
34 {
35     for (QMap<int, int>::const_iterator it = m_data.begin(); it != m_data.end(); ++it) {
36         qDebug() << "[" << (it.key() - it.value() + 1) << it.key() << "] =" << it.value();
37     }
38 }
39 
setRowRepeat(int firstRow,int rowRepeat)40 void RowRepeatStorage::setRowRepeat(int firstRow, int rowRepeat)
41 {
42    const int lastRow = firstRow + rowRepeat - 1;
43    // see if m_data contains a range that includes firstRow
44    QMap<int, int>::iterator it = m_data.lowerBound(firstRow);
45    typedef QPair<int, int> intPair;
46    QList<intPair> newRanges;
47    // returns first range that ends at or after firstRow
48    if (it != m_data.end()) {
49        while (it != m_data.end() && (it.key() - it.value() + 1) <= lastRow) {
50            if ((it.key() - it.value() + 1) < firstRow) {
51                // starts before the new range, so we want to change the row repeat value of this range
52                // but since the key is the end of the range, we can only remove it and re-insert it later
53                newRanges.append(qMakePair(firstRow - 1, it.value() - (it.key() - firstRow + 1)));
54                if (it.key() > lastRow) {
55                    // ends after the new range, so also adjust the end
56                    it.value() = it.key() - lastRow;
57                    ++it;
58                } else {
59                    it = m_data.erase(it);
60                }
61            } else {
62                // starts inside the new range, ends in or after the new range
63                if (it.key() <= lastRow) {
64                    // ends inside the new range, so just remove
65                    it = m_data.erase(it);
66                } else {
67                    // ends after the new range, adjust and go to the next
68                    it.value() = it.key() - lastRow;
69                    ++it;
70                }
71            }
72        }
73    }
74 
75    // finally set the new range of row-repeat values
76    if (rowRepeat != 1)
77        m_data[lastRow] = rowRepeat;
78 
79    foreach (const intPair& p, newRanges) {
80        if (p.second > 1) m_data[p.first] = p.second;
81    }
82 }
83 
rowRepeat(int row) const84 int RowRepeatStorage::rowRepeat(int row) const
85 {
86     // first range that ends at or after row
87     QMap<int, int>::const_iterator it = m_data.lowerBound(row);
88     // not found? default value = 1
89     if (it == m_data.end()) return 1;
90     // otherwise, see if row is actually inside the range
91     if (it.key() - it.value() + 1 <= row) {
92         return it.value();
93     }
94     return 1;
95 }
96 
firstIdenticalRow(int row) const97 int RowRepeatStorage::firstIdenticalRow(int row) const
98 {
99     // first range that ends at or after row
100     QMap<int, int>::const_iterator it = m_data.lowerBound(row);
101     // not found? default value = row
102     if (it == m_data.end()) return row;
103     // otherwise, see if row is actually inside the range
104     if (it.key() - it.value() + 1 <= row) {
105         return it.key() - it.value() + 1;
106     }
107     return row;
108 }
109 
insertRows(int row,int count)110 void RowRepeatStorage::insertRows(int row, int count)
111 {
112     typedef QPair<int, int> intPair;
113     QList<intPair> newRanges;
114 
115     // first range that ends at or after row
116     QMap<int, int>::iterator it = m_data.lowerBound(row);
117     while (it != m_data.end()) {
118         if (it.key() - it.value() + 1 < row) {
119             // starts before the newly inserted rows, so split it up
120             newRanges.append(qMakePair(row-1, row - it.key() + it.value() - 1));
121             newRanges.append(qMakePair(it.key() + count, it.key() - row + 1));
122         } else {
123             newRanges.append(qMakePair(it.key() + count, it.value()));
124         }
125         it = m_data.erase(it);
126     }
127 
128     m_data[row+count-1] = count;
129     foreach (const intPair& p, newRanges) {
130         if (p.second > 1) m_data[p.first] = p.second;
131     }
132 }
133 
removeRows(int row,int count)134 void RowRepeatStorage::removeRows(int row, int count)
135 {
136     typedef QPair<int, int> intPair;
137     QList<intPair> newRanges;
138 
139     // first range that ends at or after row
140     QMap<int, int>::iterator it = m_data.lowerBound(row);
141     while (it != m_data.end()) {
142         if (it.key() - it.value() + 1 < row) {
143             // starts before removed rows
144             newRanges.append(qMakePair(row-1, row - it.key() + it.value() - 1));
145         }
146         if (it.key() >= row + count) {
147             // ends after the removed rows
148             newRanges.append(qMakePair(it.key() - count, qMin(it.value(), it.key() - row - count + 1)));
149         }
150         it = m_data.erase(it);
151     }
152 
153     foreach (const intPair& p, newRanges) {
154         if (p.second > 1) m_data[p.first] = p.second;
155     }
156 }
157 
insertShiftDown(const QRect & rect)158 void RowRepeatStorage::insertShiftDown(const QRect &rect)
159 {
160     RowRepeatStorage s2 = *this;
161     s2.insertRows(rect.top(), rect.height());
162 
163     typedef QPair<int, int> intPair;
164     QList<intPair> newRanges;
165 
166     for (int row = 1; row <= KS_rowMax;) {
167         int repeat1 = rowRepeat(row);
168         int repeat2 = s2.rowRepeat(row);
169         repeat1 -= row - firstIdenticalRow(row);
170         repeat2 -= row - s2.firstIdenticalRow(row);
171         int repeat = qMin(repeat1, repeat2);
172         if (repeat > 1) {
173             newRanges.append(qMakePair(row + repeat - 1, repeat));
174         }
175         row += repeat;
176     }
177 
178     m_data.clear();
179     foreach (const intPair& p, newRanges) {
180         if (p.second > 1) m_data[p.first] = p.second;
181     }
182 }
183 
removeShiftUp(const QRect & rect)184 void RowRepeatStorage::removeShiftUp(const QRect &rect)
185 {
186     RowRepeatStorage s2 = *this;
187     s2.removeRows(rect.top(), rect.height());
188 
189     typedef QPair<int, int> intPair;
190     QList<intPair> newRanges;
191 
192     for (int row = 1; row <= KS_rowMax;) {
193         int repeat1 = rowRepeat(row);
194         int repeat2 = s2.rowRepeat(row);
195         repeat1 -= row - firstIdenticalRow(row);
196         repeat2 -= row - s2.firstIdenticalRow(row);
197         int repeat = qMin(repeat1, repeat2);
198         if (repeat > 1) {
199             newRanges.append(qMakePair(row + repeat - 1, repeat));
200         }
201         row += repeat;
202     }
203 
204     m_data.clear();
205     foreach (const intPair& p, newRanges) {
206         if (p.second > 1) m_data[p.first] = p.second;
207     }
208 }
209 
insertShiftRight(const QRect & rect)210 void RowRepeatStorage::insertShiftRight(const QRect &rect)
211 {
212     splitRowRepeat(rect.top());
213     splitRowRepeat(rect.bottom()+1);
214 }
215 
removeShiftLeft(const QRect & rect)216 void RowRepeatStorage::removeShiftLeft(const QRect &rect)
217 {
218     // identical to insert
219     insertShiftRight(rect);
220 }
221 
splitRowRepeat(int row)222 void RowRepeatStorage::splitRowRepeat(int row)
223 {
224     // first range that ends at or after row
225     QMap<int, int>::iterator it = m_data.lowerBound(row);
226     if (it != m_data.end() && (it.key() - it.value() + 1) < row) {
227         // range starts before row, ends in or after it; split it
228         int start = it.key() - it.value() + 1;
229         int count = row - start;
230         it.value() = it.key() - row + 1;
231         if (count > 1) m_data[start+count-1] = count;
232     }
233 }
234