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
20#include "RowFormatStorage.h"
21
22#include "calligra_sheets_limits.h"
23#include "mdds/flat_segment_tree.hpp"
24
25#include "Map.h"
26#include "RowColumnFormat.h"
27#include "Sheet.h"
28
29using namespace Calligra::Sheets;
30
31class RowFormatStorage::Private
32{
33public:
34 Private();
35 qreal rawRowHeight(int row, int* lastRow = 0, int* firstRow = 0) const;
36
37 Sheet* sheet;
38 mdds::flat_segment_tree<int, qreal> rowHeights;
39 mdds::flat_segment_tree<int, bool> hidden;
40 mdds::flat_segment_tree<int, bool> filtered;
41 mdds::flat_segment_tree<int, bool> hasPageBreak;
42};
43
44RowFormatStorage::Private::Private()
45 : rowHeights(1, KS_rowMax+1, -1)
46 , hidden(1, KS_rowMax+1, false)
47 , filtered(1, KS_rowMax+1, false)
48 , hasPageBreak(1, KS_rowMax+1, false)
49{
50}
51
52RowFormatStorage::RowFormatStorage(Sheet* sheet)
53 : d(new Private)
54{
55 d->sheet = sheet;
56}
57
58RowFormatStorage::~RowFormatStorage()
59{
60 delete d;
61}
62
63RowFormatStorage& RowFormatStorage::operator=(const RowFormatStorage& r)
64{
65 *d = *r.d;
66 return *this;
67}
68
69Sheet* RowFormatStorage::sheet() const
70{
71 return d->sheet;
72}
73
74qreal RowFormatStorage::rowHeight(int row, int *lastRow, int *firstRow) const
75{
76 qreal v = d->rawRowHeight(row, lastRow, firstRow);
77 if (v == -1) {
78 return d->sheet->map()->defaultRowFormat()->height();
79 } else {
80 return v;
81 }
82}
83
84qreal RowFormatStorage::Private::rawRowHeight(int row, int *lastRow, int *firstRow) const
85{
86 qreal v;
87 if (!rowHeights.search(row, v, firstRow, lastRow)) {
88 if (firstRow) *firstRow = row;
89 if (lastRow) *lastRow = row;
90 return -1;
91 } else {
92 if (lastRow) (*lastRow)--;
93 return v;
94 }
95}
96
97void RowFormatStorage::setRowHeight(int firstRow, int lastRow, qreal height)
98{
99 // first get old row height to properly update documentSize
100 qreal deltaHeight = -totalVisibleRowHeight(firstRow, lastRow);
101
102 d->rowHeights.insert_back(firstRow, lastRow+1, height);
103
104 deltaHeight += totalVisibleRowHeight(firstRow, lastRow);
105 d->sheet->adjustDocumentHeight(deltaHeight);
106}
107
108qreal RowFormatStorage::totalRowHeight(int firstRow, int lastRow) const
109{
110 if (lastRow < firstRow) return 0;
111 qreal res = 0;
112 for (int row = firstRow; row <= lastRow; ++row) {
113 int last;
114 qreal h = rowHeight(row, &last);
115 res += (qMin(last, lastRow) - row + 1) * h;
116 row = last;
117 }
118 return res;
119}
120
121qreal RowFormatStorage::visibleHeight(int row, int *lastRow, int *firstRow) const
122{
123 if (isHiddenOrFiltered(row, lastRow, firstRow)) {
124 return 0.0;
125 } else {
126 int hLastRow, hFirstRow;
127 qreal height = rowHeight(row, &hLastRow, &hFirstRow);
128 if (lastRow) *lastRow = qMin(*lastRow, hLastRow);
129 if (firstRow) *firstRow = qMax(*firstRow, hFirstRow);
130 return height;
131 }
132}
133
134qreal RowFormatStorage::totalVisibleRowHeight(int firstRow, int lastRow) const
135{
136 if (lastRow < firstRow) return 0;
137 qreal res = 0;
138 for (int row = firstRow; row <= lastRow; ++row) {
139 int last;
140 qreal h = visibleHeight(row, &last);
141 res += (qMin(last, lastRow) - row + 1) * h;
142 row = last;
143 }
144 return res;
145}
146
147int RowFormatStorage::rowForPosition(qreal ypos, qreal *topOfRow) const
148{
149 int row = 1;
150 qreal y = 0;
151 while (row < KS_rowMax) {
152 int last;
153 const qreal h = visibleHeight(row, &last);
154 if (h == 0) {
155 row = last+1;
156 continue;
157 }
158 const int cnt = last - row + 1;
159 const int maxcnt = qMin(int((ypos - y) / h), cnt);
160 y += maxcnt * h;
161 row += maxcnt;
162 if (maxcnt < cnt) {
163 if (topOfRow) *topOfRow = y;
164 return row;
165 }
166 }
167 return KS_rowMax;
168}
169
170bool RowFormatStorage::isHidden(int row, int *lastRow, int *firstRow) const
171{
172 bool v;
173 if (!d->hidden.search(row, v, firstRow, lastRow)) {
174 if (firstRow) *firstRow = row;
175 if (lastRow) *lastRow = row;
176 return false;
177 } else {
178 if (lastRow) (*lastRow)--;
179 return v;
180 }
181}
182
183void RowFormatStorage::setHidden(int firstRow, int lastRow, bool hidden)
184{
185 qreal deltaHeight = 0;
186 if (hidden) deltaHeight -= totalVisibleRowHeight(firstRow, lastRow);
187 d->hidden.insert_back(firstRow, lastRow+1, hidden);
188 if (!hidden) deltaHeight += totalVisibleRowHeight(firstRow, lastRow);
189 d->sheet->adjustDocumentHeight(deltaHeight);
190}
191
192bool RowFormatStorage::isFiltered(int row, int* lastRow, int *firstRow) const
193{
194 bool v;
195 if (!d->filtered.search(row, v, firstRow, lastRow)) {
196 if (firstRow) *firstRow = row;
197 if (lastRow) *lastRow = row;
198 return false;
199 } else {
200 if (lastRow) (*lastRow)--;
201 return v;
202 }
203}
204
205void RowFormatStorage::setFiltered(int firstRow, int lastRow, bool filtered)
206{
207 qreal deltaHeight = 0;
208 if (filtered) deltaHeight -= totalVisibleRowHeight(firstRow, lastRow);
209 d->filtered.insert_back(firstRow, lastRow+1, filtered);
210 if (!filtered) deltaHeight += totalVisibleRowHeight(firstRow, lastRow);
211 d->sheet->adjustDocumentHeight(deltaHeight);
212}
213
214bool RowFormatStorage::isHiddenOrFiltered(int row, int* lastRow, int* firstRow) const
215{
216 int hLastRow, hFirstRow, fLastRow, fFirstRow;
217 bool v = isHidden(row, &hLastRow, &hFirstRow);
218 v = isFiltered(row, &fLastRow, &fFirstRow) || v;
219 if (lastRow) *lastRow = qMin(hLastRow, fLastRow);
220 if (firstRow) *firstRow = qMax(hFirstRow, fFirstRow);
221 return v;
222}
223
224bool RowFormatStorage::hasPageBreak(int row, int* lastRow, int* firstRow) const
225{
226 bool v;
227 if (!d->hasPageBreak.search(row, v, firstRow, lastRow)) {
228 if (lastRow) *lastRow = row;
229 if (firstRow) *firstRow = row;
230 return false;
231 } else {
232 if (lastRow) (*lastRow)--;
233 return v;
234 }
235}
236
237void RowFormatStorage::setPageBreak(int firstRow, int lastRow, bool pageBreak)
238{
239 d->hasPageBreak.insert_back(firstRow, lastRow+1, pageBreak);
240}
241
242int RowFormatStorage::lastNonDefaultRow() const
243{
244 int row = KS_rowMax;
245 int firstRow;
246 while (row > 0 && isDefaultRow(row, 0, &firstRow)) {
247 row = firstRow-1;
248 }
249 if (row < 1) return 1;
250 return row;
251}
252
253bool RowFormatStorage::rowsAreEqual(int row1, int row2) const
254{
255 return rowHeight(row1) == rowHeight(row2)
256 && isHidden(row1) == isHidden(row2)
257 && isFiltered(row1) == isFiltered(row2)
258 && hasPageBreak(row1) == hasPageBreak(row2);
259}
260
261bool RowFormatStorage::isDefaultRow(int row, int* lastRow, int* firstRow) const
262{
263 bool isDef = true;
264 int l, f;
265 isDef = d->rawRowHeight(row, lastRow, firstRow) == -1 && isDef;
266 isDef = !isHiddenOrFiltered(row, &l, &f) && isDef;
267 if (lastRow) *lastRow = qMin(*lastRow, l);
268 if (firstRow) *firstRow = qMax(*firstRow, f);
269 isDef = !hasPageBreak(row, &l, &f) && isDef;
270 if (lastRow) *lastRow = qMin(*lastRow, l);
271 if (firstRow) *firstRow = qMax(*firstRow, f);
272 return isDef;
273}
274
275void RowFormatStorage::setDefault(int firstRow, int lastRow)
276{
277 setRowHeight(firstRow, lastRow, -1);
278 setHidden(firstRow, lastRow, false);
279 setFiltered(firstRow, lastRow, false);
280 setPageBreak(firstRow, lastRow, false);
281}
282
283void RowFormatStorage::insertRows(int row, int number)
284{
285 qreal deltaHeight = -totalRowHeight(KS_rowMax - number + 1, KS_rowMax);
286 d->rowHeights.shift_right(row, number, false);
287 deltaHeight += totalRowHeight(row, row + number - 1);
288 d->sheet->adjustDocumentHeight(deltaHeight);
289
290 d->hidden.shift_right(row, number, false);
291 d->filtered.shift_right(row, number, false);
292 d->hasPageBreak.shift_right(row, number, false);
293}
294
295void RowFormatStorage::removeRows(int row, int number)
296{
297 qreal deltaHeight = -totalRowHeight(row, row + number - 1);
298 d->rowHeights.shift_left(row, row+number-1);
299 deltaHeight += totalRowHeight(KS_rowMax - number + 1, KS_rowMax);
300 d->sheet->adjustDocumentHeight(deltaHeight);
301
302 d->hidden.shift_left(row, row+number-1);
303 d->filtered.shift_left(row, row+number-1);
304 d->hasPageBreak.shift_left(row, row+number-1);
305}
306
307