Mercurial > hg > easyhg
comparison grapher.cpp @ 106:729438d70af8
* Retrieve and store current branch and heads; some refactoring
author | Chris Cannam |
---|---|
date | Thu, 25 Nov 2010 17:54:35 +0000 |
parents | 10eb97683aa9 |
children | 4bd17f36d059 |
comparison
equal
deleted
inserted
replaced
105:1928f9b408e6 | 106:729438d70af8 |
---|---|
21 | 21 |
22 #include <QGraphicsScene> | 22 #include <QGraphicsScene> |
23 | 23 |
24 #include <iostream> | 24 #include <iostream> |
25 | 25 |
26 int | 26 int Grapher::findAvailableColumn(int row, int parent, bool preferParentCol) |
27 Grapher::findAvailableColumn(int row, int parent, bool preferParentCol) | |
28 { | 27 { |
29 int col = parent; | 28 int col = parent; |
30 if (preferParentCol) { | 29 if (preferParentCol) { |
31 if (!m_alloc[row].contains(col)) { | 30 if (!m_alloc[row].contains(col)) { |
32 return col; | 31 return col; |
33 } | 32 } |
34 } | 33 } |
35 while (col > 0) { | 34 while (col > 0) { |
36 if (!m_alloc[row].contains(--col)) return col; | 35 if (!m_alloc[row].contains(--col)) return col; |
37 } | 36 } |
38 while (col < 0) { | 37 while (col < 0) { |
39 if (!m_alloc[row].contains(++col)) return col; | 38 if (!m_alloc[row].contains(++col)) return col; |
40 } | 39 } |
41 col = parent; | 40 col = parent; |
42 int sign = (col < 0 ? -1 : 1); | 41 int sign = (col < 0 ? -1 : 1); |
43 while (1) { | 42 while (1) { |
44 col += sign; | 43 col += sign; |
45 if (!m_alloc[row].contains(col)) return col; | 44 if (!m_alloc[row].contains(col)) return col; |
46 } | 45 } |
47 } | 46 } |
48 | 47 |
49 void | 48 void Grapher::layoutRow(QString id) |
50 Grapher::layoutRow(QString id) | |
51 { | 49 { |
52 if (m_handled.contains(id)) { | 50 if (m_handled.contains(id)) { |
53 return; | 51 return; |
54 } | 52 } |
55 if (!m_changesets.contains(id)) { | 53 if (!m_changesets.contains(id)) { |
56 throw LayoutException(QString("Changeset %1 not in ID map").arg(id)); | 54 throw LayoutException(QString("Changeset %1 not in ID map").arg(id)); |
57 } | 55 } |
58 if (!m_items.contains(id)) { | 56 if (!m_items.contains(id)) { |
59 throw LayoutException(QString("Changeset %1 not in item map").arg(id)); | 57 throw LayoutException(QString("Changeset %1 not in item map").arg(id)); |
60 } | 58 } |
61 Changeset *cs = m_changesets[id]; | 59 Changeset *cs = m_changesets[id]; |
62 ChangesetItem *item = m_items[id]; | 60 ChangesetItem *item = m_items[id]; |
63 std::cerr << "layoutRow: Looking at " << id.toStdString() << std::endl; | 61 std::cerr << "layoutRow: Looking at " << id.toStdString() << std::endl; |
64 | 62 |
65 int row = 0; | 63 int row = 0; |
66 int nparents = cs->parents().size(); | 64 int nparents = cs->parents().size(); |
67 | 65 |
68 if (nparents > 0) { | 66 if (nparents > 0) { |
69 bool haveRow = false; | 67 bool haveRow = false; |
70 foreach (QString parentId, cs->parents()) { | 68 foreach (QString parentId, cs->parents()) { |
71 | 69 |
72 if (!m_changesets.contains(parentId)) continue; | 70 if (!m_changesets.contains(parentId)) continue; |
73 if (!m_items.contains(parentId)) continue; | 71 if (!m_items.contains(parentId)) continue; |
74 | 72 |
75 if (!m_handled.contains(parentId)) { | 73 if (!m_handled.contains(parentId)) { |
76 layoutRow(parentId); | 74 layoutRow(parentId); |
77 } | 75 } |
78 | 76 |
79 ChangesetItem *parentItem = m_items[parentId]; | 77 ChangesetItem *parentItem = m_items[parentId]; |
80 if (!haveRow || parentItem->row() < row) { | 78 if (!haveRow || parentItem->row() < row) { |
81 row = parentItem->row(); | 79 row = parentItem->row(); |
82 haveRow = true; | 80 haveRow = true; |
83 } | 81 } |
84 } | 82 } |
85 row = row - 1; | 83 row = row - 1; |
86 } | 84 } |
87 | 85 |
88 // row is now an upper bound on our eventual row (because we want | 86 // row is now an upper bound on our eventual row (because we want |
89 // to be above all parents). But we also want to ensure we are | 87 // to be above all parents). But we also want to ensure we are |
90 // above all nodes that have earlier dates (to the nearest day). | 88 // above all nodes that have earlier dates (to the nearest day). |
91 // m_rowDates maps each row to a date: use that. | 89 // m_rowDates maps each row to a date: use that. |
92 | 90 |
93 QString date = cs->age(); | 91 QString date = cs->age(); |
94 while (m_rowDates.contains(row) && m_rowDates[row] != date) { | 92 while (m_rowDates.contains(row) && m_rowDates[row] != date) { |
95 --row; | 93 --row; |
96 } | 94 } |
97 | 95 |
98 // We have already laid out all nodes that have earlier timestamps | 96 // We have already laid out all nodes that have earlier timestamps |
99 // than this one, so we know (among other things) that we can | 97 // than this one, so we know (among other things) that we can |
100 // safely fill in this row has having this date, if it isn't in | 98 // safely fill in this row has having this date, if it isn't in |
101 // the map yet (it cannot have an earlier date) | 99 // the map yet (it cannot have an earlier date) |
102 | 100 |
103 if (!m_rowDates.contains(row)) { | 101 if (!m_rowDates.contains(row)) { |
104 m_rowDates[row] = date; | 102 m_rowDates[row] = date; |
105 } | 103 } |
106 | 104 |
107 std::cerr << "putting " << cs->id().toStdString() << " at row " << row | 105 std::cerr << "putting " << cs->id().toStdString() << " at row " << row |
108 << std::endl; | 106 << std::endl; |
109 | 107 |
110 item->setRow(row); | 108 item->setRow(row); |
111 m_handled.insert(id); | 109 m_handled.insert(id); |
112 } | 110 } |
113 | 111 |
114 void | 112 void Grapher::layoutCol(QString id) |
115 Grapher::layoutCol(QString id) | |
116 { | 113 { |
117 if (m_handled.contains(id)) { | 114 if (m_handled.contains(id)) { |
118 std::cerr << "Already looked at " << id.toStdString() << std::endl; | 115 std::cerr << "Already looked at " << id.toStdString() << std::endl; |
119 return; | 116 return; |
120 } | 117 } |
121 if (!m_changesets.contains(id)) { | 118 if (!m_changesets.contains(id)) { |
122 throw LayoutException(QString("Changeset %1 not in ID map").arg(id)); | 119 throw LayoutException(QString("Changeset %1 not in ID map").arg(id)); |
123 } | 120 } |
124 if (!m_items.contains(id)) { | 121 if (!m_items.contains(id)) { |
125 throw LayoutException(QString("Changeset %1 not in item map").arg(id)); | 122 throw LayoutException(QString("Changeset %1 not in item map").arg(id)); |
126 } | 123 } |
127 | 124 |
128 Changeset *cs = m_changesets[id]; | 125 Changeset *cs = m_changesets[id]; |
129 std::cerr << "layoutCol: Looking at " << id.toStdString() << std::endl; | 126 std::cerr << "layoutCol: Looking at " << id.toStdString() << std::endl; |
130 | 127 |
139 int parentsOnSameBranch = 0; | 136 int parentsOnSameBranch = 0; |
140 | 137 |
141 switch (nparents) { | 138 switch (nparents) { |
142 | 139 |
143 case 0: | 140 case 0: |
144 col = m_branchHomes[cs->branch()]; | 141 col = m_branchHomes[cs->branch()]; |
145 col = findAvailableColumn(row, col, true); | 142 col = findAvailableColumn(row, col, true); |
146 break; | 143 break; |
147 | 144 |
148 case 1: | 145 case 1: |
149 parentId = cs->parents()[0]; | 146 parentId = cs->parents()[0]; |
150 | 147 |
151 if (!m_changesets.contains(parentId) || | 148 if (!m_changesets.contains(parentId) || |
152 m_changesets[parentId]->branch() != branch) { | 149 m_changesets[parentId]->branch() != branch) { |
153 // new branch | 150 // new branch |
154 col = m_branchHomes[branch]; | 151 col = m_branchHomes[branch]; |
155 } else { | 152 } else { |
156 col = m_items[parentId]->column(); | 153 col = m_items[parentId]->column(); |
157 } | 154 } |
158 | 155 |
159 col = findAvailableColumn(row, col, true); | 156 col = findAvailableColumn(row, col, true); |
160 break; | 157 break; |
161 | 158 |
162 case 2: | 159 case 2: |
163 // a merge: behave differently if parents are both on the same | 160 // a merge: behave differently if parents are both on the same |
164 // branch (we also want to behave differently for nodes that | 161 // branch (we also want to behave differently for nodes that |
165 // have multiple children on the same branch -- spreading them | 162 // have multiple children on the same branch -- spreading them |
166 // out rather than having affinity to a specific branch) | 163 // out rather than having affinity to a specific branch) |
167 | 164 |
168 foreach (QString parentId, cs->parents()) { | 165 foreach (QString parentId, cs->parents()) { |
169 if (!m_changesets.contains(parentId)) continue; | 166 if (!m_changesets.contains(parentId)) continue; |
170 if (m_changesets[parentId]->branch() == branch) { | 167 if (m_changesets[parentId]->branch() == branch) { |
171 ChangesetItem *parentItem = m_items[parentId]; | 168 ChangesetItem *parentItem = m_items[parentId]; |
172 col += parentItem->column(); | 169 col += parentItem->column(); |
173 parentsOnSameBranch++; | 170 parentsOnSameBranch++; |
174 } | 171 } |
175 } | 172 } |
176 | 173 |
177 if (parentsOnSameBranch > 0) { | 174 if (parentsOnSameBranch > 0) { |
178 col /= parentsOnSameBranch; | 175 col /= parentsOnSameBranch; |
179 col = findAvailableColumn(item->row(), col, true); | 176 col = findAvailableColumn(item->row(), col, true); |
180 } else { | 177 } else { |
181 col = findAvailableColumn(item->row(), col, false); | 178 col = findAvailableColumn(item->row(), col, false); |
182 } | 179 } |
183 break; | 180 break; |
184 } | 181 } |
185 | 182 |
186 std::cerr << "putting " << cs->id().toStdString() << " at col " << col << std::endl; | 183 std::cerr << "putting " << cs->id().toStdString() << " at col " << col << std::endl; |
187 | 184 |
188 m_alloc[row].insert(col); | 185 m_alloc[row].insert(col); |
199 // connection lines | 196 // connection lines |
200 | 197 |
201 foreach (QString childId, cs->children()) { | 198 foreach (QString childId, cs->children()) { |
202 if (!m_changesets.contains(childId)) continue; | 199 if (!m_changesets.contains(childId)) continue; |
203 Changeset *child = m_changesets[childId]; | 200 Changeset *child = m_changesets[childId]; |
204 int childRow = m_items[childId]->row(); | 201 int childRow = m_items[childId]->row(); |
205 if (child->parents().size() > 1 || | 202 if (child->parents().size() > 1 || |
206 child->branch() == cs->branch()) { | 203 child->branch() == cs->branch()) { |
207 for (int r = row-1; r > childRow; --r) { | 204 for (int r = row-1; r > childRow; --r) { |
208 m_alloc[r].insert(col); | 205 m_alloc[r].insert(col); |
209 } | 206 } |
210 } | 207 } |
211 } | 208 } |
212 | 209 |
213 // look for the case where exactly two children have the same | 210 // look for the case where exactly two children have the same |
214 // branch as us: split them to a little either side of our position | 211 // branch as us: split them to a little either side of our position |
215 | 212 |
216 if (nchildren > 1) { | 213 if (nchildren > 1) { |
217 | 214 |
218 QList<QString> special; | 215 QList<QString> special; |
219 foreach (QString childId, cs->children()) { | 216 foreach (QString childId, cs->children()) { |
220 if (!m_changesets.contains(childId)) continue; | 217 if (!m_changesets.contains(childId)) continue; |
221 Changeset *child = m_changesets[childId]; | 218 Changeset *child = m_changesets[childId]; |
222 if (child->branch() == branch && | 219 if (child->branch() == branch && |
223 child->parents().size() == 1) { | 220 child->parents().size() == 1) { |
224 special.push_back(childId); | 221 special.push_back(childId); |
225 } | 222 } |
226 } | 223 } |
227 if (special.size() == 2) { | 224 if (special.size() == 2) { |
228 for (int i = 0; i < 2; ++i) { | 225 for (int i = 0; i < 2; ++i) { |
229 int off = i * 2 - 1; // 0 -> -1, 1 -> 1 | 226 int off = i * 2 - 1; // 0 -> -1, 1 -> 1 |
230 ChangesetItem *it = m_items[special[i]]; | 227 ChangesetItem *it = m_items[special[i]]; |
231 it->setColumn(findAvailableColumn(it->row(), col + off, true)); | 228 it->setColumn(findAvailableColumn(it->row(), col + off, true)); |
232 for (int r = row-1; r >= it->row(); --r) { | 229 for (int r = row-1; r >= it->row(); --r) { |
233 m_alloc[r].insert(it->column()); | 230 m_alloc[r].insert(it->column()); |
234 } | 231 } |
235 m_handled.insert(special[i]); | 232 m_handled.insert(special[i]); |
236 } | 233 } |
237 } | 234 } |
238 } | 235 } |
239 } | 236 } |
240 | 237 |
241 bool | 238 bool Grapher::rangesConflict(const Range &r1, const Range &r2) |
242 Grapher::rangesConflict(const Range &r1, const Range &r2) | |
243 { | 239 { |
244 // allow some additional space at edges. we really ought also to | 240 // allow some additional space at edges. we really ought also to |
245 // permit space at the end of a branch up to the point where the | 241 // permit space at the end of a branch up to the point where the |
246 // merge happens | 242 // merge happens |
247 int a1 = r1.first - 2, b1 = r1.second + 2; | 243 int a1 = r1.first - 2, b1 = r1.second + 2; |
249 if (a1 > b2 || b1 < a2) return false; | 245 if (a1 > b2 || b1 < a2) return false; |
250 if (a2 > b1 || b2 < a1) return false; | 246 if (a2 > b1 || b2 < a1) return false; |
251 return true; | 247 return true; |
252 } | 248 } |
253 | 249 |
254 void | 250 void Grapher::allocateBranchHomes(Changesets csets) |
255 Grapher::allocateBranchHomes(Changesets csets) | 251 { |
256 { | 252 foreach (Changeset *cs, csets) { |
257 foreach (Changeset *cs, csets) { | 253 QString branch = cs->branch(); |
258 QString branch = cs->branch(); | 254 ChangesetItem *item = m_items[cs->id()]; |
259 ChangesetItem *item = m_items[cs->id()]; | 255 if (!item) continue; |
260 if (!item) continue; | 256 int row = item->row(); |
261 int row = item->row(); | 257 if (!m_branchRanges.contains(branch)) { |
262 if (!m_branchRanges.contains(branch)) { | 258 m_branchRanges[branch] = Range(row, row); |
263 m_branchRanges[branch] = Range(row, row); | 259 } else { |
264 } else { | 260 Range p = m_branchRanges[branch]; |
265 Range p = m_branchRanges[branch]; | 261 if (row < p.first) p.first = row; |
266 if (row < p.first) p.first = row; | 262 if (row > p.second) p.second = row; |
267 if (row > p.second) p.second = row; | 263 m_branchRanges[branch] = p; |
268 m_branchRanges[branch] = p; | 264 } |
269 } | |
270 } | 265 } |
271 | 266 |
272 m_branchHomes[""] = 0; | 267 m_branchHomes[""] = 0; |
273 | 268 |
274 foreach (QString branch, m_branchRanges.keys()) { | 269 foreach (QString branch, m_branchRanges.keys()) { |
275 if (branch == "") continue; | 270 if (branch == "") continue; |
276 QSet<int> taken; | 271 QSet<int> taken; |
277 taken.insert(0); | 272 taken.insert(0); |
278 Range myRange = m_branchRanges[branch]; | 273 Range myRange = m_branchRanges[branch]; |
279 foreach (QString other, m_branchRanges.keys()) { | 274 foreach (QString other, m_branchRanges.keys()) { |
280 if (other == branch || other == "") continue; | 275 if (other == branch || other == "") continue; |
281 Range otherRange = m_branchRanges[other]; | 276 Range otherRange = m_branchRanges[other]; |
282 if (rangesConflict(myRange, otherRange)) { | 277 if (rangesConflict(myRange, otherRange)) { |
283 if (m_branchHomes.contains(other)) { | 278 if (m_branchHomes.contains(other)) { |
284 taken.insert(m_branchHomes[other]); | 279 taken.insert(m_branchHomes[other]); |
285 } | 280 } |
286 } | 281 } |
287 } | 282 } |
288 int home = 2; | 283 int home = 2; |
289 while (taken.contains(home)) { | 284 while (taken.contains(home)) { |
290 if (home > 0) { | 285 if (home > 0) { |
291 if (home % 2 == 1) { | 286 if (home % 2 == 1) { |
292 home = -home; | 287 home = -home; |
293 } else { | 288 } else { |
294 home = home + 1; | 289 home = home + 1; |
295 } | 290 } |
296 } else { | 291 } else { |
297 if ((-home) % 2 == 1) { | 292 if ((-home) % 2 == 1) { |
298 home = home + 1; | 293 home = home + 1; |
299 } else { | 294 } else { |
300 home = -(home-2); | 295 home = -(home-2); |
301 } | 296 } |
302 } | 297 } |
303 } | 298 } |
304 m_branchHomes[branch] = home; | 299 m_branchHomes[branch] = home; |
305 } | 300 } |
306 | 301 |
307 foreach (QString branch, m_branchRanges.keys()) { | 302 foreach (QString branch, m_branchRanges.keys()) { |
308 std::cerr << branch.toStdString() << ": " << m_branchRanges[branch].first << " - " << m_branchRanges[branch].second << ", home " << m_branchHomes[branch] << std::endl; | 303 std::cerr << branch.toStdString() << ": " << m_branchRanges[branch].first << " - " << m_branchRanges[branch].second << ", home " << m_branchHomes[branch] << std::endl; |
309 } | 304 } |
310 } | 305 } |
311 | 306 |
312 static bool | 307 static bool |
313 compareChangesetsByDate(Changeset *const &a, Changeset *const &b) | 308 compareChangesetsByDate(Changeset *const &a, Changeset *const &b) |
314 { | 309 { |
315 return a->timestamp() < b->timestamp(); | 310 return a->timestamp() < b->timestamp(); |
316 } | 311 } |
317 | 312 |
318 ChangesetItem * | 313 ChangesetItem * |
319 Grapher::getItemFor(Changeset *cs) | 314 Grapher::getItemFor(Changeset *cs) |
320 { | 315 { |
321 if (!cs || !m_items.contains(cs->id())) return 0; | 316 if (!cs || !m_items.contains(cs->id())) return 0; |
322 return m_items[cs->id()]; | 317 return m_items[cs->id()]; |
323 } | 318 } |
324 | 319 |
325 void | 320 void Grapher::layout(Changesets csets) |
326 Grapher::layout(Changesets csets) | |
327 { | 321 { |
328 m_changesets.clear(); | 322 m_changesets.clear(); |
329 m_items.clear(); | 323 m_items.clear(); |
330 m_alloc.clear(); | 324 m_alloc.clear(); |
331 m_branchHomes.clear(); | 325 m_branchHomes.clear(); |
332 | 326 |
333 if (csets.empty()) return; | 327 if (csets.empty()) return; |
334 | 328 |
335 foreach (Changeset *cs, csets) { | 329 foreach (Changeset *cs, csets) { |
336 | 330 |
337 QString id = cs->id(); | 331 QString id = cs->id(); |
338 std::cerr << id.toStdString() << std::endl; | 332 std::cerr << id.toStdString() << std::endl; |
339 | 333 |
340 if (id == "") { | 334 if (id == "") { |
341 throw LayoutException("Changeset has no ID"); | 335 throw LayoutException("Changeset has no ID"); |
342 } | 336 } |
343 if (m_changesets.contains(id)) { | 337 if (m_changesets.contains(id)) { |
344 throw LayoutException(QString("Duplicate changeset ID %1").arg(id)); | 338 throw LayoutException(QString("Duplicate changeset ID %1").arg(id)); |
345 } | 339 } |
346 | 340 |
347 m_changesets[id] = cs; | 341 m_changesets[id] = cs; |
348 | 342 |
349 ChangesetItem *item = new ChangesetItem(cs); | 343 ChangesetItem *item = new ChangesetItem(cs); |
350 item->setX(0); | 344 item->setX(0); |
351 item->setY(0); | 345 item->setY(0); |
352 m_items[id] = item; | 346 m_items[id] = item; |
353 m_scene->addItem(item); | 347 m_scene->addItem(item); |
354 } | 348 } |
355 | 349 |
356 // Add the connecting lines | 350 // Add the connecting lines |
357 | 351 |
358 foreach (Changeset *cs, csets) { | 352 foreach (Changeset *cs, csets) { |
359 QString id = cs->id(); | 353 QString id = cs->id(); |
360 ChangesetItem *item = m_items[id]; | 354 ChangesetItem *item = m_items[id]; |
361 bool merge = (cs->parents().size() > 1); | 355 bool merge = (cs->parents().size() > 1); |
362 foreach (QString parentId, cs->parents()) { | 356 foreach (QString parentId, cs->parents()) { |
363 if (!m_changesets.contains(parentId)) continue; | 357 if (!m_changesets.contains(parentId)) continue; |
364 Changeset *parent = m_changesets[parentId]; | 358 Changeset *parent = m_changesets[parentId]; |
365 parent->addChild(id); | 359 parent->addChild(id); |
366 ConnectionItem *conn = new ConnectionItem(); | 360 ConnectionItem *conn = new ConnectionItem(); |
367 if (merge) conn->setConnectionType(ConnectionItem::Merge); | 361 if (merge) conn->setConnectionType(ConnectionItem::Merge); |
368 conn->setChild(item); | 362 conn->setChild(item); |
369 conn->setParent(m_items[parentId]); | 363 conn->setParent(m_items[parentId]); |
370 m_scene->addItem(conn); | 364 m_scene->addItem(conn); |
371 } | 365 } |
372 } | 366 } |
373 | 367 |
374 // Add the branch labels | 368 // Add the branch labels |
375 foreach (Changeset *cs, csets) { | 369 foreach (Changeset *cs, csets) { |
376 QString id = cs->id(); | 370 QString id = cs->id(); |
394 // above | 388 // above |
395 | 389 |
396 qStableSort(csets.begin(), csets.end(), compareChangesetsByDate); | 390 qStableSort(csets.begin(), csets.end(), compareChangesetsByDate); |
397 | 391 |
398 foreach (Changeset *cs, csets) { | 392 foreach (Changeset *cs, csets) { |
399 std::cerr << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << std::endl; | 393 std::cerr << "id " << cs->id().toStdString() << ", ts " << cs->timestamp() << ", date " << cs->datetime().toStdString() << std::endl; |
400 } | 394 } |
401 | 395 |
402 m_handled.clear(); | 396 m_handled.clear(); |
403 foreach (Changeset *cs, csets) { | 397 foreach (Changeset *cs, csets) { |
404 layoutRow(cs->id()); | 398 layoutRow(cs->id()); |
405 } | 399 } |
406 | 400 |
407 allocateBranchHomes(csets); | 401 allocateBranchHomes(csets); |
408 | 402 |
409 m_handled.clear(); | 403 m_handled.clear(); |
410 foreach (Changeset *cs, csets) { | 404 foreach (Changeset *cs, csets) { |
411 foreach (QString parentId, cs->parents()) { | 405 foreach (QString parentId, cs->parents()) { |
412 if (!m_handled.contains(parentId) && | 406 if (!m_handled.contains(parentId) && |
413 m_changesets.contains(parentId)) { | 407 m_changesets.contains(parentId)) { |
414 layoutCol(parentId); | 408 layoutCol(parentId); |
415 } | 409 } |
416 } | 410 } |
417 layoutCol(cs->id()); | 411 layoutCol(cs->id()); |
418 } | 412 } |
419 | 413 |
420 foreach (Changeset *cs, csets) { | 414 foreach (Changeset *cs, csets) { |
421 ChangesetItem *item = m_items[cs->id()]; | 415 ChangesetItem *item = m_items[cs->id()]; |
422 if (!m_alloc[item->row()].contains(item->column()-1) && | 416 if (!m_alloc[item->row()].contains(item->column()-1) && |
423 !m_alloc[item->row()].contains(item->column()+1)) { | 417 !m_alloc[item->row()].contains(item->column()+1)) { |
424 item->setWide(true); | 418 item->setWide(true); |
425 } | 419 } |
426 } | 420 } |
427 | 421 |
428 // we know that 0 is an upper bound on row, and that mincol must | 422 // we know that 0 is an upper bound on row, and that mincol must |
429 // be <= 0 and maxcol >= 0, so these initial values are good | 423 // be <= 0 and maxcol >= 0, so these initial values are good |
430 int minrow = 0, maxrow = 0; | 424 int minrow = 0, maxrow = 0; |
431 int mincol = 0, maxcol = 0; | 425 int mincol = 0, maxcol = 0; |
432 | 426 |
433 foreach (int r, m_alloc.keys()) { | 427 foreach (int r, m_alloc.keys()) { |
434 if (r < minrow) minrow = r; | 428 if (r < minrow) minrow = r; |
435 if (r > maxrow) maxrow = r; | 429 if (r > maxrow) maxrow = r; |
436 ColumnSet &c = m_alloc[r]; | 430 ColumnSet &c = m_alloc[r]; |
437 foreach (int i, c) { | 431 foreach (int i, c) { |
438 if (i < mincol) mincol = i; | 432 if (i < mincol) mincol = i; |
439 if (i > maxcol) maxcol = i; | 433 if (i > maxcol) maxcol = i; |
440 } | 434 } |
441 } | 435 } |
442 | 436 |
443 QString prevDate; | 437 QString prevDate; |
444 int changeRow = 0; | 438 int changeRow = 0; |
445 | 439 |
446 bool even = false; | 440 bool even = false; |
447 int n = 0; | 441 int n = 0; |
448 | 442 |
449 for (int row = minrow; row <= maxrow; ++row) { | 443 for (int row = minrow; row <= maxrow; ++row) { |
450 | 444 |
451 QString date = m_rowDates[row]; | 445 QString date = m_rowDates[row]; |
452 n++; | 446 n++; |
453 | 447 |
454 if (date != prevDate) { | 448 if (date != prevDate) { |
455 if (prevDate != "") { | 449 if (prevDate != "") { |
456 DateItem *item = new DateItem(); | 450 DateItem *item = new DateItem(); |
457 item->setDateString(prevDate); | 451 item->setDateString(prevDate); |
458 item->setCols(mincol, maxcol - mincol + 1); | 452 item->setCols(mincol, maxcol - mincol + 1); |
459 item->setRows(changeRow, n); | 453 item->setRows(changeRow, n); |
460 item->setEven(even); | 454 item->setEven(even); |
461 item->setZValue(-1); | 455 item->setZValue(-1); |
462 m_scene->addItem(item); | 456 m_scene->addItem(item); |
463 even = !even; | 457 even = !even; |
464 } | 458 } |
465 prevDate = date; | 459 prevDate = date; |
466 changeRow = row; | 460 changeRow = row; |
467 n = 0; | 461 n = 0; |
468 } | 462 } |
469 } | 463 } |
470 | 464 |
471 if (n > 0) { | 465 if (n > 0) { |
472 DateItem *item = new DateItem(); | 466 DateItem *item = new DateItem(); |
473 item->setDateString(prevDate); | 467 item->setDateString(prevDate); |
474 item->setCols(mincol, maxcol - mincol + 1); | 468 item->setCols(mincol, maxcol - mincol + 1); |
475 item->setRows(changeRow, n+1); | 469 item->setRows(changeRow, n+1); |
476 item->setEven(even); | 470 item->setEven(even); |
477 item->setZValue(-1); | 471 item->setZValue(-1); |
478 m_scene->addItem(item); | 472 m_scene->addItem(item); |
479 even = !even; | 473 even = !even; |
480 } | 474 } |
481 } | 475 } |
482 | 476 |