]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/kitemset.cpp
Fix selection rect after porting from QFontMetrics::width()
[dolphin.git] / src / kitemviews / kitemset.cpp
1 /***************************************************************************
2 * Copyright (C) 2013 by Frank Reininghaus <frank78ac@googlemail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program 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 *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "kitemset.h"
21
22
23 KItemSet::iterator KItemSet::insert(int i)
24 {
25 if (m_itemRanges.empty()) {
26 m_itemRanges.push_back(KItemRange(i, 1));
27 return iterator(m_itemRanges.begin(), 0);
28 }
29
30 KItemRangeList::iterator rangeBegin = m_itemRanges.begin();
31 if (i < rangeBegin->index) {
32 // The inserted index is smaller than all existing items.
33 if (i == rangeBegin->index - 1) {
34 // Move the beginning of the first range one item to the front.
35 --rangeBegin->index;
36 ++rangeBegin->count;
37 } else {
38 // Insert a new range at the beginning.
39 rangeBegin = m_itemRanges.insert(rangeBegin, KItemRange(i, 1));
40 }
41
42 return iterator(rangeBegin, 0);
43 }
44
45 KItemRangeList::iterator rangeEnd = m_itemRanges.end();
46 KItemRangeList::iterator lastRange = rangeEnd - 1;
47 if (i >= lastRange->index) {
48 // i either belongs to the last range, or it is larger than all existing items.
49 const int lastItemPlus1 = lastRange->index + lastRange->count;
50 if (i == lastItemPlus1) {
51 // Move the end of the last range one item to the back.
52 ++lastRange->count;
53 } else if (i > lastItemPlus1) {
54 // Append a new range.
55 lastRange = m_itemRanges.insert(rangeEnd, KItemRange(i, 1));
56 }
57
58 return iterator(lastRange, i - lastRange->index);
59 }
60
61 // We know that i is between the smallest existing item and the first item
62 // of the last range. Find the lowest range whose 'index' is smaller than i.
63 KItemRangeList::iterator low = rangeBegin;
64 KItemRangeList::iterator high = lastRange;
65
66 while (low + 1 != high) {
67 const int span = high - low;
68 Q_ASSERT(span >= 2);
69
70 KItemRangeList::iterator mid = low + span / 2;
71 if (mid->index > i) {
72 high = mid;
73 } else {
74 low = mid;
75 }
76 }
77
78 Q_ASSERT(low->index <= i && high->index > i);
79
80 if (i == low->index + low->count) {
81 // i is just one item behind the range low.
82 if (i == high->index - 1) {
83 // i closes the gap between low and high. Merge the two ranges.
84 const int newRangeCount = low->count + 1 + high->count;
85 KItemRangeList::iterator behindNewRange = m_itemRanges.erase(high);
86 KItemRangeList::iterator newRange = behindNewRange - 1;
87 newRange->count = newRangeCount;
88 return iterator(newRange, i - newRange->index);
89 } else {
90 // Extend low by one item.
91 ++low->count;
92 return iterator(low, low->count - 1);
93 }
94 } else if (i > low->index + low->count) {
95 if (i == high->index - 1) {
96 // Extend high by one item to the front.
97 --high->index;
98 ++high->count;
99 return iterator(high, 0);
100 } else {
101 // Insert a new range between low and high.
102 KItemRangeList::iterator newRange = m_itemRanges.insert(high, KItemRange(i, 1));
103 return iterator(newRange, 0);
104 }
105 } else {
106 // The range low already contains i.
107 return iterator(low, i - low->index);
108 }
109 }
110
111 KItemSet::iterator KItemSet::erase(iterator it)
112 {
113 KItemRangeList::iterator rangeIt = it.m_rangeIt;
114
115 if (it.m_offset == 0) {
116 // Removed index is at the beginning of a range.
117 if (rangeIt->count > 1) {
118 ++rangeIt->index;
119 --rangeIt->count;
120 } else {
121 // The range only contains the removed index.
122 rangeIt = m_itemRanges.erase(rangeIt);
123 }
124 return iterator(rangeIt, 0);
125 } else if (it.m_offset == rangeIt->count - 1) {
126 // Removed index is at the end of a range.
127 --rangeIt->count;
128 ++rangeIt;
129 return iterator(rangeIt, 0);
130 } else {
131 // The removed index is in the middle of a range.
132 const int newRangeIndex = *it + 1;
133 const int newRangeCount = rangeIt->count - it.m_offset - 1;
134 const KItemRange newRange(newRangeIndex, newRangeCount);
135
136 rangeIt->count = it.m_offset;
137 ++rangeIt;
138 rangeIt = m_itemRanges.insert(rangeIt, newRange);
139
140 return iterator(rangeIt, 0);
141 }
142 }
143
144 KItemSet KItemSet::operator+(const KItemSet& other) const
145 {
146 KItemSet sum;
147
148 KItemRangeList::const_iterator it1 = m_itemRanges.constBegin();
149 KItemRangeList::const_iterator it2 = other.m_itemRanges.constBegin();
150
151 const KItemRangeList::const_iterator end1 = m_itemRanges.constEnd();
152 const KItemRangeList::const_iterator end2 = other.m_itemRanges.constEnd();
153
154 while (it1 != end1 || it2 != end2) {
155 if (it1 == end1) {
156 // We are past the end of 'this' already. Append all remaining
157 // item ranges from 'other'.
158 while (it2 != end2) {
159 sum.m_itemRanges.append(*it2);
160 ++it2;
161 }
162 } else if (it2 == end2) {
163 // We are past the end of 'other' already. Append all remaining
164 // item ranges from 'this'.
165 while (it1 != end1) {
166 sum.m_itemRanges.append(*it1);
167 ++it1;
168 }
169 } else {
170 // Find the beginning of the next range.
171 int index = qMin(it1->index, it2->index);
172 int count = 0;
173
174 do {
175 if (it1 != end1 && it1->index <= index + count) {
176 // The next range from 'this' overlaps with the current range in the sum.
177 count = qMax(count, it1->index + it1->count - index);
178 ++it1;
179 }
180
181 if (it2 != end2 && it2->index <= index + count) {
182 // The next range from 'other' overlaps with the current range in the sum.
183 count = qMax(count, it2->index + it2->count - index);
184 ++it2;
185 }
186 } while ((it1 != end1 && it1->index <= index + count)
187 || (it2 != end2 && it2->index <= index + count));
188
189 sum.m_itemRanges.append(KItemRange(index, count));
190 }
191 }
192
193 return sum;
194 }
195
196 KItemSet KItemSet::operator^(const KItemSet& other) const
197 {
198 // We are looking for all ints which are either in *this or in other,
199 // but not in both.
200 KItemSet result;
201
202 // When we go through all integers from INT_MIN to INT_MAX and start
203 // in the state "do not add to result", every beginning/end of a range
204 // of *this and other toggles the "add/do not add to result" state.
205 // Therefore, we just have to put ints where any range starts/ends to
206 // a sorted array, and then we can calculate the result quite easily.
207 QVector<int> rangeBoundaries;
208 rangeBoundaries.resize(2 * (m_itemRanges.count() + other.m_itemRanges.count()));
209 const QVector<int>::iterator begin = rangeBoundaries.begin();
210 const QVector<int>::iterator end = rangeBoundaries.end();
211 QVector<int>::iterator it = begin;
212
213 foreach (const KItemRange& range, m_itemRanges) {
214 *it++ = range.index;
215 *it++ = range.index + range.count;
216 }
217
218 const QVector<int>::iterator middle = it;
219
220 foreach (const KItemRange& range, other.m_itemRanges) {
221 *it++ = range.index;
222 *it++ = range.index + range.count;
223 }
224 Q_ASSERT(it == end);
225
226 std::inplace_merge(begin, middle, end);
227
228 it = begin;
229 while (it != end) {
230 const int rangeBegin = *it;
231 ++it;
232
233 if (*it == rangeBegin) {
234 // It seems that ranges from both *this and other start at
235 // rangeBegin. Do not start a new range, but read the next int.
236 //
237 // Example: Consider the symmetric difference of the sets
238 // {1, 2, 3, 4} and {1, 2}. The sorted list of range boundaries is
239 // 1 1 3 5. Discarding the duplicate 1 yields the result
240 // rangeBegin = 3, rangeEnd = 5, which corresponds to the set {3, 4}.
241 ++it;
242 } else {
243 // The end of the current range is the next *single* int that we
244 // find. If an int appears twice in rangeBoundaries, the range does
245 // not end.
246 //
247 // Example: Consider the symmetric difference of the sets
248 // {1, 2, 3, 4, 8, 9, 10} and {5, 6, 7}. The sorted list of range
249 // boundaries is 1 5 5 8 8 11, and discarding all duplicates yields
250 // the result rangeBegin = 1, rangeEnd = 11, which corresponds to
251 // the set {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}.
252 bool foundEndOfRange = false;
253 int rangeEnd;
254 do {
255 rangeEnd = *it;
256 ++it;
257
258 if (it == end || *it != rangeEnd) {
259 foundEndOfRange = true;
260 } else {
261 ++it;
262 }
263 } while (!foundEndOfRange);
264
265 result.m_itemRanges.append(KItemRange(rangeBegin, rangeEnd - rangeBegin));
266 }
267 }
268
269 return result;
270 }
271
272 bool KItemSet::isValid() const
273 {
274 const KItemRangeList::const_iterator begin = m_itemRanges.constBegin();
275 const KItemRangeList::const_iterator end = m_itemRanges.constEnd();
276
277 for (KItemRangeList::const_iterator it = begin; it != end; ++it) {
278 if (it->count <= 0) {
279 return false;
280 }
281
282 if (it != begin) {
283 const KItemRangeList::const_iterator previous = it - 1;
284 if (previous->index + previous->count >= it->index) {
285 return false;
286 }
287 }
288 }
289
290 return true;
291 }
292
293 KItemRangeList::iterator KItemSet::rangeForItem(int i)
294 {
295 const KItemRangeList::iterator end = m_itemRanges.end();
296 KItemRangeList::iterator low = m_itemRanges.begin();
297 KItemRangeList::iterator high = end;
298
299 if (low == end || low->index > i) {
300 return end;
301 }
302
303 while (low != high && low + 1 != high) {
304 KItemRangeList::iterator mid = low + (high - low) / 2;
305 if (mid->index > i) {
306 high = mid;
307 } else {
308 low = mid;
309 }
310 }
311
312 Q_ASSERT(low->index <= i);
313 if (low->index + low->count > i) {
314 return low;
315 }
316
317 return end;
318 }
319
320 KItemRangeList::const_iterator KItemSet::constRangeForItem(int i) const
321 {
322 const KItemRangeList::const_iterator end = m_itemRanges.constEnd();
323 KItemRangeList::const_iterator low = m_itemRanges.constBegin();
324 KItemRangeList::const_iterator high = end;
325
326 if (low == end || low->index > i) {
327 return end;
328 }
329
330 while (low != high && low + 1 != high) {
331 KItemRangeList::const_iterator mid = low + (high - low) / 2;
332 if (mid->index > i) {
333 high = mid;
334 } else {
335 low = mid;
336 }
337 }
338
339 Q_ASSERT(low->index <= i);
340 if (low->index + low->count > i) {
341 return low;
342 }
343
344 return end;
345 }