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"
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()));
154 m_columns = createColumns();
155 connect(m_columns, SIGNAL(sortOutDated()),
this, SLOT(sort()));
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) {
183 m_columns->getSortingOrder().first());
186 QFuture< QList< AbstractTreeItem * > > future =
187 QtConcurrent::run(&AbstractTableModel::doSort,
this,
189 m_sortingWatcher->setFuture(future);
191 emit modelModified();
197 void AbstractTableModel::reverseOrder(
TableColumn *column) {
201 void AbstractTableModel::updateSort() {
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(
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";
263 throw IException(IException::Programmer, msg, _FILEINFO_);
266 AbstractTreeItem *end = item2;
272 void (QList< AbstractTreeItem * >::*someKindaPend)(AbstractTreeItem *);
273 someKindaPend = &QList< AbstractTreeItem * >::append;
275 if (start == item2) {
277 someKindaPend = &QList< AbstractTreeItem * >::prepend;
280 while (currentIndex < m_sortedItems->size() &&
281 m_sortedItems->at(currentIndex) != end) {
282 (sortedSubsetOfItems.*someKindaPend)(m_sortedItems->at(currentIndex));
286 if (currentIndex >= m_sortedItems->size()) {
287 IString msg =
"Could not find the second item";
288 throw IException(IException::Programmer, msg, _FILEINFO_);
291 (sortedSubsetOfItems.*someKindaPend)(end);
294 return sortedSubsetOfItems;
298 void AbstractTableModel::handleTreeSelectionChanged(
299 QList< AbstractTreeItem * > newlySelectedItems,
300 AbstractTreeItem::InternalPointerType pointerType) {
301 QList< AbstractTreeItem * > interestingSelectedItems;
302 foreach (AbstractTreeItem * item, newlySelectedItems) {
303 if (item->getPointerType() == pointerType)
304 interestingSelectedItems.append(item);
307 if (interestingSelectedItems.size()) {
308 emit treeSelectionChanged(interestingSelectedItems);
313 void AbstractTableModel::sortStatusUpdated() {
314 if (m_lessThanFunctor)
315 emit sortProgressChanged(m_lessThanFunctor->getCompareCount());
319 void AbstractTableModel::sortFinished() {
320 bool interrupted = m_lessThanFunctor->interrupted();
321 delete m_lessThanFunctor;
322 m_lessThanFunctor = NULL;
325 QList< AbstractTreeItem * > newSortedItems = m_sortingWatcher->result();
327 if (!m_dataModel->isFiltering() && !m_dataModel->isRebuilding()) {
328 *m_sortedItems = newSortedItems;
329 emit modelModified();
338 void AbstractTableModel::cancelSort() {
339 if (m_lessThanFunctor) {
340 m_lessThanFunctor->interrupt();
341 m_sortingWatcher->waitForFinished();
346 void AbstractTableModel::itemsLost() {
348 m_sortedItems->clear();
352 QList< AbstractTreeItem * > AbstractTableModel::doSort(
353 QList< AbstractTreeItem * > itemsToSort) {
357 QList< TableColumn * > columnsToSortOn = m_columns->getSortingOrder();
361 m_sortStatusPoller->start(SORT_UPDATE_FREQUENCY);
365 int numItems = itemsToSort.size();
368 emit sortProgressRangeChanged(0,
369 (
int)((a * numItems) * (log2(b * numItems))));
372 std::stable_sort(itemsToSort.begin(), itemsToSort.end(),
376 m_sortStatusPoller->stop();
377 emit sortProgressRangeChanged(0, 0);
378 emit sortProgressChanged(0);
379 emit modelModified();
382 return QList< AbstractTreeItem * >();
388 m_sortStatusPoller->stop();
389 emit sortProgressRangeChanged(0, 0);
390 emit sortProgressChanged(0);
391 emit modelModified();
401 void AbstractTableModel::nullify() {
404 m_sortedItems = NULL;
406 m_sortStatusPoller = NULL;
407 m_lessThanFunctor = NULL;
409 m_sortingWatcher = NULL;
413 void AbstractTableModel::setSorting(
bool isSorting) {
414 m_sorting = isSorting;
418 void AbstractTableModel::rebuildSort() {
419 m_sortedItems->clear();
423 m_sortingEnabled =
false;
424 *m_sortedItems = getItems(0, -1);
426 foreach (AbstractTreeItem * item, *m_sortedItems) {
427 connect(item, SIGNAL(destroyed(QObject *)),
this, SLOT(itemsLost()));
430 m_sortingEnabled =
true;
433 emit userWarning(None);
437 emit modelModified();
439 if (!m_sortingEnabled)
440 emit userWarning(SortingDisabled);
442 emit userWarning(SortingTableSizeLimitReached);
450 AbstractTableModel::LessThanFunctor::LessThanFunctor(
451 TableColumn const *someColumn) : m_column(someColumn) {
452 m_sharedData =
new LessThanFunctorData;
456 AbstractTableModel::LessThanFunctor::LessThanFunctor(
457 LessThanFunctor
const &other) : m_sharedData(other.m_sharedData) {
458 m_column = other.m_column;
462 AbstractTableModel::LessThanFunctor::~LessThanFunctor() {
467 int AbstractTableModel::LessThanFunctor::getCompareCount()
const {
468 return m_sharedData->getCompareCount();
472 void AbstractTableModel::LessThanFunctor::interrupt() {
473 m_sharedData->setInterrupted(
true);
477 bool AbstractTableModel::LessThanFunctor::interrupted() {
478 return m_sharedData->interrupted();
482 void AbstractTableModel::LessThanFunctor::reset() {
483 m_sharedData->setInterrupted(
false);
487 bool AbstractTableModel::LessThanFunctor::operator()(
488 AbstractTreeItem *
const &left, AbstractTreeItem *
const &right) {
489 if (left->getPointerType() != right->getPointerType()) {
490 IString msg =
"Tried to compare apples to oranges";
491 throw IException(IException::Programmer, msg, _FILEINFO_);
494 if (m_sharedData->interrupted()) {
495 throw SortingCanceledException();
498 m_sharedData->incrementCompareCount();
500 QVariant leftData = left->getData(m_column->getTitle());
501 QVariant rightData = right->getData(m_column->getTitle());
502 QString busy = BusyLeafItem().getData().toString();
505 if (leftData.type() == QVariant::String &&
506 rightData.type() == QVariant::String) {
507 lessThan = leftData.toString() < rightData.toString();
509 else if (leftData.type() == QVariant::Double &&
510 rightData.type() == QVariant::Double) {
511 lessThan = (leftData.toDouble() < rightData.toDouble());
513 else if (leftData.type() == QVariant::Double ||
514 rightData.type() == QVariant::Double) {
517 lessThan = (leftData.toString() == busy);
520 lessThan = leftData.toString() < rightData.toString();
523 return lessThan ^ m_column->sortAscending();
527 AbstractTableModel::LessThanFunctor &
528 AbstractTableModel::LessThanFunctor::operator=(
529 LessThanFunctor
const &other) {
530 if (
this != &other) {
531 m_column = other.m_column;
532 m_sharedData = other.m_sharedData;
542 AbstractTableModel::LessThanFunctorData::LessThanFunctorData() {
543 m_compareCount.fetchAndStoreRelaxed(0);
544 m_interruptFlag.fetchAndStoreRelaxed(0);
548 AbstractTableModel::LessThanFunctorData::LessThanFunctorData(
549 LessThanFunctorData
const &other) :
QSharedData(other),
550 m_compareCount(other.m_compareCount), m_interruptFlag(other.m_interruptFlag) {
554 AbstractTableModel::LessThanFunctorData::~LessThanFunctorData() {
558 int AbstractTableModel::LessThanFunctorData::getCompareCount()
const {
559 return m_compareCount;
563 void AbstractTableModel::LessThanFunctorData::incrementCompareCount() {
564 m_compareCount.fetchAndAddRelaxed(1);
568 void AbstractTableModel::LessThanFunctorData::setInterrupted(
bool newStatus) {
569 newStatus ? m_interruptFlag.fetchAndStoreRelaxed(1) :
570 m_interruptFlag.fetchAndStoreRelaxed(0);
574 bool AbstractTableModel::LessThanFunctorData::interrupted() {
575 return m_interruptFlag != 0;
Base class for delegates which create, read, and save data in the tables.
Thread-safe exception for cancelling sorting.
Base class for an item in the tree.
Base class for tree models.
This is free and unencumbered software released into the public domain.