12#include <QCoreApplication>
15#include <QFutureWatcher>
17#include <QtConcurrentRun>
20#include "IException.h"
23#include "AbstractTableDelegate.h"
24#include "AbstractTableModel.h"
25#include "BusyLeafItem.h"
26#include "TableColumn.h"
27#include "TableColumnList.h"
29#include "AbstractTreeModel.h"
33 AbstractTableModel::AbstractTableModel(AbstractTreeModel *model,
34 AbstractTableDelegate *someDelegate) {
38 connect(model, SIGNAL(cancelSort()),
this, SLOT(cancelSort()));
40 m_delegate = someDelegate;
42 m_sortingEnabled =
false;
46 m_sortedItems =
new QList<AbstractTreeItem *>;
47 m_busyItem =
new BusyLeafItem;
48 m_sortStatusPoller =
new QTimer;
50 m_sortingWatcher =
new QFutureWatcher< QList< AbstractTreeItem * > >;
51 connect(m_sortingWatcher, SIGNAL(finished()),
this, SLOT(sortFinished()));
53 connect(m_sortStatusPoller, SIGNAL(timeout()),
54 this, SLOT(sortStatusUpdated()));
57 connect(model, SIGNAL(modelModified()), SLOT(rebuildSort()));
59 connect(model, SIGNAL(filterProgressChanged(
int)),
60 this, SIGNAL(filterProgressChanged(
int)));
62 connect(model, SIGNAL(rebuildProgressChanged(
int)),
63 this, SIGNAL(rebuildProgressChanged(
int)));
65 connect(model, SIGNAL(filterProgressRangeChanged(
int,
int)),
66 this, SIGNAL(filterProgressRangeChanged(
int,
int)));
68 connect(model, SIGNAL(rebuildProgressRangeChanged(
int,
int)),
69 this, SIGNAL(rebuildProgressRangeChanged(
int,
int)));
71 connect(
this, SIGNAL(tableSelectionChanged(QList<AbstractTreeItem *>)),
72 model, SIGNAL(tableSelectionChanged(QList<AbstractTreeItem *>)));
73 connect(model, SIGNAL(filterCountsChanged(
int,
int)),
74 this, SIGNAL(filterCountsChanged(
int,
int)));
78 AbstractTableModel::~AbstractTableModel() {
92 delete m_sortStatusPoller;
93 m_sortStatusPoller = NULL;
95 delete m_lessThanFunctor;
96 m_lessThanFunctor = NULL;
99 for (
int i = 0; i < m_columns->size(); i++)
100 delete(*m_columns)[i];
106 delete m_sortingWatcher;
107 m_sortingWatcher = NULL;
111 bool AbstractTableModel::isSorting()
const {
116 bool AbstractTableModel::isFiltering()
const {
117 return m_dataModel && m_dataModel->isFiltering();
121 bool AbstractTableModel::sortingIsEnabled()
const {
122 return m_sortingEnabled;
126 void AbstractTableModel::setSortingEnabled(
bool enabled) {
127 if (m_sortingEnabled != enabled) {
128 m_sortingEnabled = enabled;
134 int AbstractTableModel::sortLimit()
const {
139 void AbstractTableModel::setSortLimit(
int limit) {
140 if (m_sortLimit != limit) {
147 bool AbstractTableModel::sortingOn()
const {
148 return (sortingIsEnabled() && (getVisibleRowCount() <= sortLimit()));
152 TableColumnList *AbstractTableModel::getColumns() {
154 m_columns = createColumns();
155 connect(m_columns, SIGNAL(sortOutDated()),
this, SLOT(sort()));
162 const AbstractTableDelegate *AbstractTableModel::getDelegate()
const {
167 void AbstractTableModel::applyFilter() {
168 getDataModel()->applyFilter();
172 void AbstractTableModel::sort() {
173 if (sortingOn() && m_sortedItems->size() && !m_dataModel->isFiltering() &&
174 !m_dataModel->isRebuilding()) {
178 else if (!m_lessThanFunctor) {
182 m_lessThanFunctor =
new LessThanFunctor(
183 m_columns->getSortingOrder().first());
186 QFuture< QList< AbstractTreeItem * > > future =
187 QtConcurrent::run(
this, &AbstractTableModel::doSort,
189 m_sortingWatcher->setFuture(future);
191 emit modelModified();
197 void AbstractTableModel::reverseOrder(TableColumn *column) {
201 void AbstractTableModel::updateSort() {
205 AbstractTreeModel *AbstractTableModel::getDataModel() {
210 const AbstractTreeModel *AbstractTableModel::getDataModel()
const {
215 QList< AbstractTreeItem * > AbstractTableModel::getSortedItems(
216 int start,
int end, AbstractTreeModel::InterestingItems flags) {
217 QList< AbstractTreeItem * > sortedSubsetOfItems;
220 while (start <= end) {
221 if (start < m_sortedItems->size())
222 sortedSubsetOfItems.append(m_sortedItems->at(start));
223 else if (isFiltering())
224 sortedSubsetOfItems.append(m_busyItem);
230 sortedSubsetOfItems = getDataModel()->getItems(start, end, flags,
true);
233 return sortedSubsetOfItems;
237 QList< AbstractTreeItem * > AbstractTableModel::getSortedItems(
238 AbstractTreeItem *item1, AbstractTreeItem *item2,
239 AbstractTreeModel::InterestingItems flags) {
240 QList< AbstractTreeItem * > sortedSubsetOfItems;
243 sortedSubsetOfItems = getDataModel()->getItems(item1, item2, flags,
true);
246 AbstractTreeItem *start = NULL;
248 int currentIndex = 0;
250 while (!start && currentIndex < m_sortedItems->size()) {
251 AbstractTreeItem *current = m_sortedItems->at(currentIndex);
252 if (current == item1)
254 else if (current == item2)
262 IString msg =
"Could not find the first item";
266 AbstractTreeItem *end = item2;
272 void (QList< AbstractTreeItem * >::*someKindaPend)(
273 AbstractTreeItem * const &);
276 if (start == item2) {
281 while (currentIndex < m_sortedItems->size() &&
282 m_sortedItems->at(currentIndex) != end) {
283 (sortedSubsetOfItems.*someKindaPend)(m_sortedItems->at(currentIndex));
287 if (currentIndex >= m_sortedItems->size()) {
288 IString msg =
"Could not find the second item";
292 (sortedSubsetOfItems.*someKindaPend)(end);
295 return sortedSubsetOfItems;
299 void AbstractTableModel::handleTreeSelectionChanged(
300 QList< AbstractTreeItem * > newlySelectedItems,
301 AbstractTreeItem::InternalPointerType pointerType) {
302 QList< AbstractTreeItem * > interestingSelectedItems;
303 foreach (AbstractTreeItem * item, newlySelectedItems) {
304 if (item->getPointerType() == pointerType)
305 interestingSelectedItems.append(item);
308 if (interestingSelectedItems.size()) {
309 emit treeSelectionChanged(interestingSelectedItems);
314 void AbstractTableModel::sortStatusUpdated() {
315 if (m_lessThanFunctor)
316 emit sortProgressChanged(m_lessThanFunctor->getCompareCount());
320 void AbstractTableModel::sortFinished() {
321 bool interrupted = m_lessThanFunctor->interrupted();
322 delete m_lessThanFunctor;
323 m_lessThanFunctor = NULL;
326 QList< AbstractTreeItem * > newSortedItems = m_sortingWatcher->result();
328 if (!m_dataModel->isFiltering() && !m_dataModel->isRebuilding()) {
329 *m_sortedItems = newSortedItems;
330 emit modelModified();
339 void AbstractTableModel::cancelSort() {
340 if (m_lessThanFunctor) {
341 m_lessThanFunctor->interrupt();
342 m_sortingWatcher->waitForFinished();
347 void AbstractTableModel::itemsLost() {
349 m_sortedItems->clear();
353 QList< AbstractTreeItem * > AbstractTableModel::doSort(
354 QList< AbstractTreeItem * > itemsToSort) {
358 QList< TableColumn * > columnsToSortOn = m_columns->getSortingOrder();
362 m_sortStatusPoller->start(SORT_UPDATE_FREQUENCY);
366 int numItems = itemsToSort.size();
369 emit sortProgressRangeChanged(0,
370 (
int)((a * numItems) * (log2(b * numItems))));
373 std::stable_sort(itemsToSort.begin(), itemsToSort.end(),
376 catch (SortingCanceledException &e) {
377 m_sortStatusPoller->stop();
378 emit sortProgressRangeChanged(0, 0);
379 emit sortProgressChanged(0);
380 emit modelModified();
383 return QList< AbstractTreeItem * >();
389 m_sortStatusPoller->stop();
390 emit sortProgressRangeChanged(0, 0);
391 emit sortProgressChanged(0);
392 emit modelModified();
402 void AbstractTableModel::nullify() {
405 m_sortedItems = NULL;
407 m_sortStatusPoller = NULL;
408 m_lessThanFunctor = NULL;
410 m_sortingWatcher = NULL;
414 void AbstractTableModel::setSorting(
bool isSorting) {
415 m_sorting = isSorting;
419 void AbstractTableModel::rebuildSort() {
420 m_sortedItems->clear();
424 m_sortingEnabled =
false;
425 *m_sortedItems = getItems(0, -1);
427 foreach (AbstractTreeItem * item, *m_sortedItems) {
428 connect(item, SIGNAL(destroyed(
QObject *)),
this, SLOT(itemsLost()));
431 m_sortingEnabled =
true;
434 emit userWarning(None);
438 emit modelModified();
440 if (!m_sortingEnabled)
441 emit userWarning(SortingDisabled);
443 emit userWarning(SortingTableSizeLimitReached);
451 AbstractTableModel::LessThanFunctor::LessThanFunctor(
452 TableColumn
const *someColumn) : m_column(someColumn) {
453 m_sharedData =
new LessThanFunctorData;
457 AbstractTableModel::LessThanFunctor::LessThanFunctor(
458 LessThanFunctor
const &other) : m_sharedData(other.m_sharedData) {
459 m_column = other.m_column;
463 AbstractTableModel::LessThanFunctor::~LessThanFunctor() {
468 int AbstractTableModel::LessThanFunctor::getCompareCount()
const {
469 return m_sharedData->getCompareCount();
473 void AbstractTableModel::LessThanFunctor::interrupt() {
474 m_sharedData->setInterrupted(
true);
478 bool AbstractTableModel::LessThanFunctor::interrupted() {
479 return m_sharedData->interrupted();
483 void AbstractTableModel::LessThanFunctor::reset() {
484 m_sharedData->setInterrupted(
false);
488 bool AbstractTableModel::LessThanFunctor::operator()(
489 AbstractTreeItem *
const &left, AbstractTreeItem *
const &right) {
490 if (left->getPointerType() != right->getPointerType()) {
491 IString msg =
"Tried to compare apples to oranges";
492 throw IException(IException::Programmer, msg, _FILEINFO_);
495 if (m_sharedData->interrupted()) {
496 throw SortingCanceledException();
499 m_sharedData->incrementCompareCount();
501 QVariant leftData = left->getData(m_column->getTitle());
502 QVariant rightData = right->getData(m_column->getTitle());
503 QString busy = BusyLeafItem().getData().toString();
506 if (leftData.type() == QVariant::String &&
507 rightData.type() == QVariant::String) {
508 lessThan = leftData.toString() < rightData.toString();
510 else if (leftData.type() == QVariant::Double &&
511 rightData.type() == QVariant::Double) {
512 lessThan = (leftData.toDouble() < rightData.toDouble());
514 else if (leftData.type() == QVariant::Double ||
515 rightData.type() == QVariant::Double) {
518 lessThan = (leftData.toString() == busy);
521 lessThan = leftData.toString() < rightData.toString();
524 return lessThan ^ m_column->sortAscending();
528 AbstractTableModel::LessThanFunctor &
529 AbstractTableModel::LessThanFunctor::operator=(
530 LessThanFunctor
const &other) {
531 if (
this != &other) {
532 m_column = other.m_column;
533 m_sharedData = other.m_sharedData;
543 AbstractTableModel::LessThanFunctorData::LessThanFunctorData() {
544 m_compareCount.fetchAndStoreRelaxed(0);
545 m_interruptFlag.fetchAndStoreRelaxed(0);
549 AbstractTableModel::LessThanFunctorData::LessThanFunctorData(
550 LessThanFunctorData
const &other) :
QSharedData(other),
551 m_compareCount(other.m_compareCount), m_interruptFlag(other.m_interruptFlag) {
555 AbstractTableModel::LessThanFunctorData::~LessThanFunctorData() {
559 int AbstractTableModel::LessThanFunctorData::getCompareCount()
const {
560 return m_compareCount;
564 void AbstractTableModel::LessThanFunctorData::incrementCompareCount() {
565 m_compareCount.fetchAndAddRelaxed(1);
569 void AbstractTableModel::LessThanFunctorData::setInterrupted(
bool newStatus) {
570 newStatus ? m_interruptFlag.fetchAndStoreRelaxed(1) :
571 m_interruptFlag.fetchAndStoreRelaxed(0);
575 bool AbstractTableModel::LessThanFunctorData::interrupted() {
576 return m_interruptFlag != 0;
@ Programmer
This error is for when a programmer made an API call that was illegal.
This is free and unencumbered software released into the public domain.
This is free and unencumbered software released into the public domain.