1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 #include <iostream>
7 
8 #include "Wt/WAggregateProxyModel.h"
9 #include "Wt/WException.h"
10 
11 namespace {
contains2(int a1,int a2,int b1,int b2)12   bool contains2(int a1, int a2, int b1, int b2) {
13     return b1 >= a1 && b1 <= a2 && b2 >= a1 && b2 <= a2;
14   }
15 
overlaps(int a1,int a2,int b1,int b2)16   bool overlaps(int a1, int a2, int b1, int b2) {
17     return !((a2 < b1) || (a1 > b2));
18   }
19 
nestingError(int pa,int a1,int a2,int pb,int b1,int b2)20   std::string nestingError(int pa, int a1, int a2, int pb, int b1, int b2) {
21     std::stringstream msg;
22 
23     msg
24       << "WAggregateProxyModel: aggregates must strictly nest: ["
25       << pa << ": " << a1 << " - " << a2 << "] overlaps partially with ["
26       << pb << ": " << b1 << " - " << b2 << "]";
27 
28     return msg.str();
29   }
30 }
31 
32 namespace Wt {
33 
Aggregate()34 WAggregateProxyModel::Aggregate::Aggregate()
35   : parentSrc_(-1),
36     firstChildSrc_(-1),
37     lastChildSrc_(-1),
38     level_(0),
39     collapsed_(false)
40 { }
41 
Aggregate(int parentColumn,int firstColumn,int lastColumn)42 WAggregateProxyModel::Aggregate::Aggregate(int parentColumn,
43 					   int firstColumn, int lastColumn)
44   : parentSrc_(parentColumn),
45     firstChildSrc_(firstColumn),
46     lastChildSrc_(lastColumn),
47     level_(0),
48     collapsed_(false)
49 {
50   if (parentSrc_ != firstChildSrc_ - 1 && parentSrc_ != lastChildSrc_ + 1)
51     throw WException("WAggregateProxyModel::addAggregate: parent column "
52 		     "must border children range");
53 }
54 
contains(const Aggregate & other)55 bool WAggregateProxyModel::Aggregate::contains(const Aggregate& other) const
56 {
57   int pa = parentSrc_, a1 = firstChildSrc_, a2 = lastChildSrc_,
58     pb = other.parentSrc_, b1 = other.firstChildSrc_, b2 = other.lastChildSrc_;
59 
60   if (pb >= a1 && pb <= a2) {
61     if (!::contains2(a1, a2, b1, b2))
62       throw WException(nestingError(pa, a1, a2, pb, b1, b2));
63 
64     return true;
65   } else {
66     if (::overlaps(a1, a2, b1, b2))
67       throw WException(nestingError(pa, a1, a2, pb, b1, b2));
68 
69     return false;
70   }
71 }
72 
73 WAggregateProxyModel::Aggregate *
add(const Aggregate & toAdd)74 WAggregateProxyModel::Aggregate::add(const Aggregate& toAdd)
75 {
76   for (unsigned int i = 0; i < nestedAggregates_.size(); ++i) {
77     Aggregate& a = nestedAggregates_[i];
78 
79     if (a.contains(toAdd))
80       return a.add(toAdd);
81 
82     if (toAdd.before(a)) {
83       nestedAggregates_.insert(nestedAggregates_.begin() + i, toAdd);
84       nestedAggregates_[i].level_ = level_ + 1;
85       return &nestedAggregates_[i];
86     }
87   }
88 
89   nestedAggregates_.push_back(toAdd);
90   nestedAggregates_.back().level_ = level_ + 1;
91   return &nestedAggregates_.back();
92 }
93 
94 WAggregateProxyModel::Aggregate *
findAggregate(int parentColumn)95 WAggregateProxyModel::Aggregate::findAggregate(int parentColumn)
96 {
97   if (parentSrc_ == parentColumn)
98     return this;
99   else if (parentSrc_ != -1 && parentColumn > lastChildSrc_)
100     return nullptr;
101   else {
102     for (unsigned int i = 0; i < nestedAggregates_.size(); ++i) {
103       Aggregate& a = nestedAggregates_[i];
104 
105       Aggregate *result = a.findAggregate(parentColumn);
106       if (result)
107 	return result;
108     }
109   }
110 
111   return nullptr;
112 }
113 
114 const WAggregateProxyModel::Aggregate *
findAggregate(int parentColumn)115 WAggregateProxyModel::Aggregate::findAggregate(int parentColumn) const
116 {
117   return const_cast<Aggregate *>(this)->findAggregate(parentColumn);
118 }
119 
120 const WAggregateProxyModel::Aggregate *
findEnclosingAggregate(int column)121 WAggregateProxyModel::Aggregate::findEnclosingAggregate(int column) const
122 {
123   for (unsigned int i = 0; i < nestedAggregates_.size(); ++i) {
124     const Aggregate& a = nestedAggregates_[i];
125 
126     if (a.after(column))
127       return this;
128 
129     if (a.contains(column))
130       return a.findEnclosingAggregate(column);
131   }
132 
133   return this;
134 }
135 
mapFromSource(int sourceColumn)136 int WAggregateProxyModel::Aggregate::mapFromSource(int sourceColumn) const
137 {
138   int collapsedCount = 0;
139 
140   for (unsigned i = 0; i < nestedAggregates_.size(); ++i) {
141     const Aggregate& a = nestedAggregates_[i];
142 
143     if (a.after(sourceColumn))
144       return sourceColumn - collapsedCount;
145     else if (a.contains(sourceColumn))
146       if (a.collapsed_)
147 	return -1;
148       else
149 	return a.mapFromSource(sourceColumn) - collapsedCount;
150     else // a < sourceColumn
151       collapsedCount += a.collapsedCount();
152   }
153 
154   return sourceColumn - collapsedCount;
155 }
156 
mapToSource(int column)157 int WAggregateProxyModel::Aggregate::mapToSource(int column) const
158 {
159   int sourceColumn = column;
160 
161   for (unsigned i = 0; i < nestedAggregates_.size(); ++i) {
162     const Aggregate& a = nestedAggregates_[i];
163 
164     if (a.after(sourceColumn))
165       return sourceColumn;
166     else if (!a.collapsed_ && a.contains(sourceColumn))
167       return a.mapToSource(sourceColumn);
168     else
169       sourceColumn += a.collapsedCount();
170   }
171 
172   return sourceColumn;
173 }
174 
before(const Aggregate & other)175 bool WAggregateProxyModel::Aggregate::before(const Aggregate& other) const
176 {
177   return lastChildSrc_ < other.firstChildSrc_;
178 }
179 
after(int column)180 bool WAggregateProxyModel::Aggregate::after(int column) const
181 {
182   return firstChildSrc_ > column;
183 }
184 
before(int column)185 bool WAggregateProxyModel::Aggregate::before(int column) const
186 {
187   return lastChildSrc_ < column;
188 }
189 
contains(int sourceColumn)190 bool WAggregateProxyModel::Aggregate::contains(int sourceColumn) const
191 {
192   return firstChildSrc_ <= sourceColumn && sourceColumn <= lastChildSrc_;
193 }
194 
collapsedCount()195 int WAggregateProxyModel::Aggregate::collapsedCount() const
196 {
197   if (collapsed_)
198     return lastChildSrc_ - firstChildSrc_ + 1;
199   else {
200     int result = 0;
201 
202     for (unsigned i = 0; i < nestedAggregates_.size(); ++i) {
203       const Aggregate& a = nestedAggregates_[i];
204 
205       result += a.collapsedCount();
206     }
207 
208     return result;
209   }
210 }
211 
firstVisibleNotBefore(int column)212 int WAggregateProxyModel::Aggregate::firstVisibleNotBefore(int column) const
213 {
214   if (collapsed_)
215     return lastChildSrc_ + 1;
216   else {
217     for (unsigned i = 0; i < nestedAggregates_.size(); ++i) {
218       const Aggregate& a = nestedAggregates_[i];
219 
220       if (a.after(column))
221 	return column;
222       else if (a.before(column))
223 	continue;
224       else
225 	column = a.firstVisibleNotBefore(column);
226     }
227 
228     return column;
229   }
230 }
231 
lastVisibleNotAfter(int column)232 int WAggregateProxyModel::Aggregate::lastVisibleNotAfter(int column) const
233 {
234   if (collapsed_)
235     return firstChildSrc_ - 1;
236   else {
237     for (int i = nestedAggregates_.size() - 1; i >= 0; --i) {
238       const Aggregate& a = nestedAggregates_[i];
239 
240       if (a.before(column))
241 	return column;
242       else if (a.after(column))
243 	continue;
244       else
245 	column = a.lastVisibleNotAfter(column);
246     }
247 
248     return column;
249   }
250 }
251 
WAggregateProxyModel()252 WAggregateProxyModel::WAggregateProxyModel()
253   : topLevel_()
254 { }
255 
~WAggregateProxyModel()256 WAggregateProxyModel::~WAggregateProxyModel()
257 { }
258 
259 void WAggregateProxyModel
setSourceModel(const std::shared_ptr<WAbstractItemModel> & model)260 ::setSourceModel(const std::shared_ptr<WAbstractItemModel>& model)
261 {
262   for (unsigned i = 0; i < modelConnections_.size(); ++i)
263     modelConnections_[i].disconnect();
264   modelConnections_.clear();
265 
266   WAbstractProxyModel::setSourceModel(model);
267 
268   modelConnections_.push_back(sourceModel()->columnsAboutToBeInserted().connect
269      (this, &WAggregateProxyModel::sourceColumnsAboutToBeInserted));
270   modelConnections_.push_back(sourceModel()->columnsInserted().connect
271      (this, &WAggregateProxyModel::sourceColumnsInserted));
272 
273   modelConnections_.push_back(sourceModel()->columnsAboutToBeRemoved().connect
274      (this, &WAggregateProxyModel::sourceColumnsAboutToBeRemoved));
275   modelConnections_.push_back(sourceModel()->columnsRemoved().connect
276      (this, &WAggregateProxyModel::sourceColumnsRemoved));
277 
278   modelConnections_.push_back(sourceModel()->rowsAboutToBeInserted().connect
279      (this, &WAggregateProxyModel::sourceRowsAboutToBeInserted));
280   modelConnections_.push_back(sourceModel()->rowsInserted().connect
281      (this, &WAggregateProxyModel::sourceRowsInserted));
282 
283   modelConnections_.push_back(sourceModel()->rowsAboutToBeRemoved().connect
284      (this, &WAggregateProxyModel::sourceRowsAboutToBeRemoved));
285   modelConnections_.push_back(sourceModel()->rowsRemoved().connect
286      (this, &WAggregateProxyModel::sourceRowsRemoved));
287 
288   modelConnections_.push_back(sourceModel()->dataChanged().connect
289      (this, &WAggregateProxyModel::sourceDataChanged));
290   modelConnections_.push_back(sourceModel()->headerDataChanged().connect
291      (this, &WAggregateProxyModel::sourceHeaderDataChanged));
292 
293   modelConnections_.push_back(sourceModel()->layoutAboutToBeChanged().connect
294      (this, &WAggregateProxyModel::sourceLayoutAboutToBeChanged));
295   modelConnections_.push_back(sourceModel()->layoutChanged().connect
296      (this, &WAggregateProxyModel::sourceLayoutChanged));
297 
298   modelConnections_.push_back(sourceModel()->modelReset().connect
299      (this, &WAggregateProxyModel::sourceModelReset));
300 
301   topLevel_ = Aggregate();
302 }
303 
addAggregate(int parentColumn,int firstColumn,int lastColumn)304 void WAggregateProxyModel::addAggregate(int parentColumn,
305 					int firstColumn, int lastColumn)
306 {
307   Aggregate *added
308     = topLevel_.add(Aggregate(parentColumn, firstColumn, lastColumn));
309 
310   collapse(*added);
311 }
312 
propagateBeginRemove(const WModelIndex & proxyIndex,int start,int end)313 void WAggregateProxyModel::propagateBeginRemove(const WModelIndex& proxyIndex,
314 						int start, int end)
315 {
316   // should be beginRemoveColumns(), but endRemoveColumns() calls cannot
317   // be nested
318   columnsAboutToBeRemoved().emit(proxyIndex, start, end);
319 
320   unsigned int rc = rowCount(proxyIndex);
321   for (unsigned i = 0; i < rc; ++i)
322     propagateBeginRemove(index(i, 0, proxyIndex), start, end);
323 }
324 
propagateEndRemove(const WModelIndex & proxyIndex,int start,int end)325 void WAggregateProxyModel::propagateEndRemove(const WModelIndex& proxyIndex,
326 					      int start, int end)
327 {
328   // should be endRemoveColumns(), but endRemoveColumns() calls cannot
329   // be nested
330   columnsRemoved().emit(proxyIndex, start, end);
331 
332   unsigned int rc = rowCount(proxyIndex);
333   for (unsigned i = 0; i < rc; ++i)
334     propagateEndRemove(index(i, 0, proxyIndex), start, end);
335 }
336 
propagateBeginInsert(const WModelIndex & proxyIndex,int start,int end)337 void WAggregateProxyModel::propagateBeginInsert(const WModelIndex& proxyIndex,
338 						int start, int end)
339 {
340   // should be beginInsertColumns(), but endInsertColumns() calls cannot
341   // be nested
342   columnsAboutToBeInserted().emit(proxyIndex, start, end);
343 
344   unsigned int rc = rowCount(proxyIndex);
345   for (unsigned i = 0; i < rc; ++i)
346     propagateBeginInsert(index(i, 0, proxyIndex), start, end);
347 }
348 
propagateEndInsert(const WModelIndex & proxyIndex,int start,int end)349 void WAggregateProxyModel::propagateEndInsert(const WModelIndex& proxyIndex,
350 					      int start, int end)
351 {
352   // should be endInsertColumns(), but endInsertColumns() calls cannot
353   // be nested
354   columnsInserted().emit(proxyIndex, start, end);
355 
356   unsigned int rc = rowCount(proxyIndex);
357   for (unsigned i = 0; i < rc; ++i)
358     propagateEndInsert(index(i, 0, proxyIndex), start, end);
359 }
360 
expandColumn(int column)361 void WAggregateProxyModel::expandColumn(int column)
362 {
363   int sourceColumn = topLevel_.mapToSource(column);
364   Aggregate *ag = topLevel_.findAggregate(sourceColumn);
365 
366   if (ag)
367     expand(*ag);
368 }
369 
collapseColumn(int column)370 void WAggregateProxyModel::collapseColumn(int column)
371 {
372   int sourceColumn = topLevel_.mapToSource(column);
373   Aggregate *ag = topLevel_.findAggregate(sourceColumn);
374 
375   if (ag)
376     collapse(*ag);
377 }
378 
expand(Aggregate & aggregate)379 void WAggregateProxyModel::expand(Aggregate& aggregate)
380 {
381   int c = topLevel_.mapFromSource(aggregate.parentSrc_);
382   if (c >= 0) {
383     aggregate.collapsed_ = false;
384     int c1 = topLevel_.mapFromSource(firstVisibleSourceNotBefore
385 				     (aggregate.firstChildSrc_));
386     int c2 = topLevel_.mapFromSource(lastVisibleSourceNotAfter
387 				     (aggregate.lastChildSrc_));
388     aggregate.collapsed_ = true;
389 
390     propagateBeginInsert(WModelIndex(), c1, c2);
391     aggregate.collapsed_ = false;
392     propagateEndInsert(WModelIndex(), c1, c2);
393   } else
394     aggregate.collapsed_ = false;
395 }
396 
collapse(Aggregate & aggregate)397 void WAggregateProxyModel::collapse(Aggregate& aggregate)
398 {
399   int c = topLevel_.mapFromSource(aggregate.parentSrc_);
400   if (c >= 0) {
401     int c1 = topLevel_.mapFromSource(firstVisibleSourceNotBefore
402 				     (aggregate.firstChildSrc_));
403     int c2 = topLevel_.mapFromSource(lastVisibleSourceNotAfter
404 				     (aggregate.lastChildSrc_));
405 
406     propagateBeginRemove(WModelIndex(), c1, c2);
407     aggregate.collapsed_ = true;
408     propagateEndRemove(WModelIndex(), c1, c2);
409   } else
410     aggregate.collapsed_ = true;
411 }
412 
mapFromSource(const WModelIndex & sourceIndex)413 WModelIndex WAggregateProxyModel::mapFromSource(const WModelIndex& sourceIndex)
414   const
415 {
416   if (sourceIndex.isValid()) {
417     int column = topLevel_.mapFromSource(sourceIndex.column());
418     if (column >= 0) {
419       int row = sourceIndex.row();
420 
421       return createIndex(row, column, sourceIndex.internalPointer());
422     } else
423       return WModelIndex();
424   } else
425     return WModelIndex();
426 }
427 
mapToSource(const WModelIndex & proxyIndex)428 WModelIndex WAggregateProxyModel::mapToSource(const WModelIndex& proxyIndex)
429   const
430 {
431   if (proxyIndex.isValid()) {
432     int column = topLevel_.mapToSource(proxyIndex.column());
433     int row = proxyIndex.row();
434 
435     return createSourceIndex(row, column, proxyIndex.internalPointer());
436   } else
437     return WModelIndex();
438 }
439 
index(int row,int column,const WModelIndex & parent)440 WModelIndex WAggregateProxyModel::index(int row, int column,
441 					const WModelIndex& parent) const
442 {
443   WModelIndex sourceParent = mapToSource(parent);
444   int sourceRow = row;
445   int sourceColumn = topLevel_.mapToSource(column);
446 
447   WModelIndex sourceIndex
448     = sourceModel()->index(sourceRow, sourceColumn, sourceParent);
449 
450   return createIndex(row, column,
451 		     sourceIndex.isValid() ? sourceIndex.internalPointer() :
452 		     nullptr);
453 }
454 
parent(const WModelIndex & index)455 WModelIndex WAggregateProxyModel::parent(const WModelIndex& index) const
456 {
457   if (index.isValid())
458     return mapFromSource(mapToSource(index).parent());
459   else
460     return WModelIndex();
461 }
462 
columnCount(const WModelIndex & parent)463 int WAggregateProxyModel::columnCount(const WModelIndex& parent) const
464 {
465   int c = sourceModel()->columnCount(mapToSource(parent));
466   if (c > 0) {
467     c = lastVisibleSourceNotAfter(c - 1);
468     return topLevel_.mapFromSource(c) + 1;
469   } else
470     return 0;
471 }
472 
rowCount(const WModelIndex & parent)473 int WAggregateProxyModel::rowCount(const WModelIndex& parent) const
474 {
475   return sourceModel()->rowCount(mapToSource(parent));
476 }
477 
sort(int column,Wt::SortOrder order)478 void WAggregateProxyModel::sort(int column, Wt::SortOrder order)
479 {
480   sourceModel()->sort(topLevel_.mapToSource(column), order);
481 }
482 
headerData(int section,Orientation orientation,ItemDataRole role)483 cpp17::any WAggregateProxyModel::headerData(int section,
484                                      Orientation orientation, ItemDataRole role) const
485 {
486   if (orientation == Orientation::Horizontal) {
487     section = topLevel_.mapToSource(section);
488     if (role == ItemDataRole::Level) {
489       const Aggregate *agg = topLevel_.findEnclosingAggregate(section);
490       return cpp17::any(agg->level_);
491     } else
492       return sourceModel()->headerData(section, orientation, role);
493   } else
494     return sourceModel()->headerData(section, orientation, role);
495 }
496 
setHeaderData(int section,Orientation orientation,const cpp17::any & value,ItemDataRole role)497 bool WAggregateProxyModel::setHeaderData(int section, Orientation orientation,
498                                          const cpp17::any& value, ItemDataRole role)
499 {
500   if (orientation == Orientation::Horizontal)
501     section = topLevel_.mapToSource(section);
502 
503   return sourceModel()->setHeaderData(section, orientation, value, role);
504 }
505 
headerFlags(int section,Orientation orientation)506 WFlags<HeaderFlag> WAggregateProxyModel::headerFlags(int section,
507 						     Orientation orientation)
508   const
509 {
510   if (orientation == Orientation::Horizontal) {
511     int srcColumn = topLevel_.mapToSource(section);
512 
513     WFlags<HeaderFlag> result
514       = sourceModel()->headerFlags(srcColumn, orientation);
515 
516     const Aggregate *agg = topLevel_.findAggregate(srcColumn);
517     if (agg) {
518       if (agg->collapsed_)
519 	return result | HeaderFlag::ColumnIsCollapsed;
520       else
521 	if (agg->parentSrc_ == agg->lastChildSrc_ + 1)
522 	  return result | HeaderFlag::ColumnIsExpandedLeft;
523 	else // agg->parentSrc_ == firstChildSrc_ - 1
524 	  return result | HeaderFlag::ColumnIsExpandedRight;
525     } else
526       return result;
527   } else
528     return sourceModel()->headerFlags(section, orientation);
529 }
530 
sourceColumnsAboutToBeInserted(const WModelIndex & parent,int start,int end)531 void WAggregateProxyModel::sourceColumnsAboutToBeInserted
532   (const WModelIndex& parent, int start, int end)
533 {
534   throw WException("WAggregateProxyModel does not support "
535 		   "source model column insertion");
536 }
537 
sourceColumnsInserted(const WModelIndex & parent,int start,int end)538 void WAggregateProxyModel::sourceColumnsInserted(const WModelIndex& parent,
539 						 int start, int end)
540 {
541   throw WException("WAggregateProxyModel does not support "
542 		   "source model column insertion");
543 }
544 
sourceColumnsAboutToBeRemoved(const WModelIndex & parent,int start,int end)545 void WAggregateProxyModel::sourceColumnsAboutToBeRemoved
546   (const WModelIndex& parent, int start, int end)
547 {
548   throw WException("WAggregateProxyModel does not support "
549 		   "source model column removal");
550 }
551 
sourceColumnsRemoved(const WModelIndex & parent,int start,int end)552 void WAggregateProxyModel::sourceColumnsRemoved(const WModelIndex& parent,
553 						int start, int end)
554 {
555   throw WException("WAggregateProxyModel does not support "
556 		   "source model column removal");
557 }
558 
sourceRowsAboutToBeInserted(const WModelIndex & parent,int start,int end)559 void WAggregateProxyModel::sourceRowsAboutToBeInserted
560   (const WModelIndex& parent, int start, int end)
561 {
562   WModelIndex proxyParent = mapFromSource(parent);
563 
564   if (proxyParent.isValid() || !parent.isValid())
565     beginInsertRows(proxyParent, start, end);
566 }
567 
sourceRowsInserted(const WModelIndex & parent,int start,int end)568 void WAggregateProxyModel::sourceRowsInserted(const WModelIndex& parent,
569 					      int start, int end)
570 {
571   WModelIndex proxyParent = mapFromSource(parent);
572 
573   if (proxyParent.isValid() || !parent.isValid())
574     endInsertRows();
575 }
576 
sourceRowsAboutToBeRemoved(const WModelIndex & parent,int start,int end)577 void WAggregateProxyModel::sourceRowsAboutToBeRemoved
578 (const WModelIndex& parent, int start, int end)
579 {
580   WModelIndex proxyParent = mapFromSource(parent);
581 
582   if (proxyParent.isValid() || !parent.isValid())
583     beginRemoveRows(proxyParent, start, end);
584 }
585 
sourceRowsRemoved(const WModelIndex & parent,int start,int end)586 void WAggregateProxyModel::sourceRowsRemoved(const WModelIndex& parent,
587 					      int start, int end)
588 {
589   WModelIndex proxyParent = mapFromSource(parent);
590 
591   if (proxyParent.isValid() || !parent.isValid())
592     endRemoveRows();
593 }
594 
firstVisibleSourceNotBefore(int column)595 int WAggregateProxyModel::firstVisibleSourceNotBefore(int column) const
596 {
597   return topLevel_.firstVisibleNotBefore(column);
598 }
599 
lastVisibleSourceNotAfter(int column)600 int WAggregateProxyModel::lastVisibleSourceNotAfter(int column) const
601 {
602   return topLevel_.lastVisibleNotAfter(column);
603 }
604 
sourceDataChanged(const WModelIndex & topLeft,const WModelIndex & bottomRight)605 void WAggregateProxyModel::sourceDataChanged(const WModelIndex& topLeft,
606 					     const WModelIndex& bottomRight)
607 {
608   int l = firstVisibleSourceNotBefore(topLeft.column());
609   int r = lastVisibleSourceNotAfter(bottomRight.column());
610 
611   if (r >= l) {
612     WModelIndex tl = mapFromSource(sourceModel()->index(topLeft.row(),
613 							l,
614 							topLeft.parent()));
615     WModelIndex br = mapFromSource(sourceModel()->index(bottomRight.row(),
616 							r,
617 							bottomRight.parent()));
618     dataChanged().emit(tl, br);
619   }
620 }
621 
sourceHeaderDataChanged(Orientation orientation,int start,int end)622 void WAggregateProxyModel::sourceHeaderDataChanged(Orientation orientation,
623 						   int start, int end)
624 {
625   if (orientation == Orientation::Vertical) {
626     headerDataChanged().emit(orientation, start, end);
627   } else {
628     int l = firstVisibleSourceNotBefore(start);
629     int r = lastVisibleSourceNotAfter(end);
630 
631     if (r >= l) {
632       l = topLevel_.mapFromSource(l);
633       r = topLevel_.mapFromSource(r);
634 
635       headerDataChanged().emit(orientation, l, r);
636     }
637   }
638 }
639 
sourceLayoutAboutToBeChanged()640 void WAggregateProxyModel::sourceLayoutAboutToBeChanged()
641 {
642   layoutAboutToBeChanged().emit();
643 }
644 
sourceLayoutChanged()645 void WAggregateProxyModel::sourceLayoutChanged()
646 {
647   layoutChanged().emit();
648 }
649 
sourceModelReset()650 void WAggregateProxyModel::sourceModelReset()
651 {
652   topLevel_ = Aggregate();
653   reset();
654 }
655 
656 }
657