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
27using namespace Calligra::Sheets;
28
29RowRepeatStorage::RowRepeatStorage()
30{
31}
32
33void 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
40void 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
84int 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
97int 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
110void 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
134void 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
158void 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
184void 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
210void RowRepeatStorage::insertShiftRight(const QRect &rect)
211{
212 splitRowRepeat(rect.top());
213 splitRowRepeat(rect.bottom()+1);
214}
215
216void RowRepeatStorage::removeShiftLeft(const QRect &rect)
217{
218 // identical to insert
219 insertShiftRight(rect);
220}
221
222void 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