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.