You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Editor/Util/ColumnSortProxyModel.cpp

285 lines
7.1 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "ColumnSortProxyModel.h"
// Editor
#include "Util/AbstractSortModel.h"
class ColumnSortProxyModelLessThan
{
public:
inline ColumnSortProxyModelLessThan(int column, const AbstractSortModel* source)
: sort_column(column)
, source_model(source) {}
inline bool operator()(int r1, int r2) const
{
QModelIndex i1 = source_model->index(r1, sort_column);
QModelIndex i2 = source_model->index(r2, sort_column);
return source_model->LessThan(i1, i2);
}
private:
int sort_column;
const AbstractSortModel* source_model;
};
class ColumnSortProxyModelGreaterThan
{
public:
inline ColumnSortProxyModelGreaterThan(int column, const AbstractSortModel* source)
: sort_column(column)
, source_model(source) {}
inline bool operator()(int r1, int r2) const
{
QModelIndex i1 = source_model->index(r1, sort_column);
QModelIndex i2 = source_model->index(r2, sort_column);
return source_model->LessThan(i2, i1);
}
private:
int sort_column;
const AbstractSortModel* source_model;
};
ColumnSortProxyModel::ColumnSortProxyModel(QObject* parent)
: QAbstractProxyModel(parent)
{
}
ColumnSortProxyModel::~ColumnSortProxyModel()
{
}
QVariant ColumnSortProxyModel::data(const QModelIndex& index, int role) const
{
Q_ASSERT(index.isValid() && index.model() == this);
return sourceModel()->data(mapToSource(index), role);
}
QVariant ColumnSortProxyModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return sourceModel()->headerData(section, orientation, role);
}
int ColumnSortProxyModel::rowCount(const QModelIndex& index) const
{
if (!sourceModel() || index.isValid())
{
return 0;
}
return sourceModel()->rowCount(index);
}
int ColumnSortProxyModel::columnCount(const QModelIndex& index) const
{
if (!sourceModel() || index.isValid())
{
return 0;
}
return sourceModel()->columnCount(index);
}
QModelIndex ColumnSortProxyModel::index(int row, int column, const QModelIndex& parent) const
{
Q_UNUSED(parent);
Q_ASSERT(!parent.isValid());
return createIndex(row, column);
}
QModelIndex ColumnSortProxyModel::parent(const QModelIndex& index) const
{
Q_UNUSED(index);
return QModelIndex();
}
QModelIndex ColumnSortProxyModel::mapFromSource(const QModelIndex& sourceIndex) const
{
Q_ASSERT(!sourceIndex.isValid() || sourceIndex.model() == sourceModel());
if (!sourceIndex.isValid())
{
return QModelIndex();
}
int row = m_mappingToSource.indexOf(sourceIndex.row());
return createIndex(row, sourceIndex.column());
}
QModelIndex ColumnSortProxyModel::mapToSource(const QModelIndex& proxyIndex) const
{
Q_ASSERT(!proxyIndex.isValid() || proxyIndex.model() == this);
if (!proxyIndex.isValid())
{
return QModelIndex();
}
int row = m_mappingToSource.at(proxyIndex.row());
return sourceModel()->index(row, proxyIndex.column());
}
void ColumnSortProxyModel::setSourceModel(QAbstractItemModel* sourceModel)
{
Q_ASSERT(qobject_cast<AbstractSortModel*>(sourceModel));
QAbstractProxyModel::setSourceModel(sourceModel);
connect(sourceModel, &QAbstractItemModel::rowsInserted, this, &ColumnSortProxyModel::SortModel);
connect(sourceModel, &QAbstractItemModel::rowsRemoved, this, &ColumnSortProxyModel::SortModel);
connect(sourceModel, &QAbstractItemModel::modelAboutToBeReset, this, &ColumnSortProxyModel::beginResetModel);
connect(sourceModel, &QAbstractItemModel::modelReset, this, [=]()
{
{ QSignalBlocker sb(this);
SortModel();
} endResetModel();
});
connect(sourceModel, &QAbstractItemModel::layoutChanged, this, &ColumnSortProxyModel::SortModel);
connect(sourceModel, &QAbstractItemModel::dataChanged, this, &ColumnSortProxyModel::SourceDataChanged);
SortModel();
}
void ColumnSortProxyModel::sort(int column, Qt::SortOrder order)
{
int id = ColumnContains(column);
if (id == -1)
{
AddColumn(column, order);
}
else
{
if (m_columns.at(id).sortOrder != order)
{
m_columns[id].sortOrder = order;
SortModel();
}
}
}
void ColumnSortProxyModel::AddColumn(int column, Qt::SortOrder order)
{
if (ColumnContains(column) == -1)
{
m_columns.push_front({ column, order });
SortModel();
}
}
void ColumnSortProxyModel::AddColumnWithoutSorting(int column, Qt::SortOrder order)
{
if (ColumnContains(column) == -1)
{
m_columns.push_front({ column, order });
}
}
void ColumnSortProxyModel::RemoveColumn(int column)
{
int id = ColumnContains(column);
if (id != -1)
{
m_columns.remove(id);
SortModel();
}
}
void ColumnSortProxyModel::RemoveColumnWithoutSorting(int column)
{
int id = ColumnContains(column);
if (id != -1)
{
m_columns.remove(id);
}
}
void ColumnSortProxyModel::SetColumns(const QVector<int>& columns)
{
m_columns.clear();
foreach(int col, columns)
{
m_columns.push_back({ col, Qt::AscendingOrder });
}
SortModel();
}
void ColumnSortProxyModel::ClearColumns()
{
SortModel();
}
bool ColumnSortProxyModel::IsColumnSorted(int col) const
{
int id = ColumnContains(col);
return (id != -1);
}
Qt::SortOrder ColumnSortProxyModel::SortOrder(int col) const
{
int id = ColumnContains(col);
if (id != -1)
{
return m_columns.at(id).sortOrder;
}
return Qt::AscendingOrder;
}
void ColumnSortProxyModel::SortModel()
{
emit layoutAboutToBeChanged();
int size = sourceModel() ? sourceModel()->rowCount() : 0;
m_mappingToSource.resize(size);
for (int i = 0; i < size; ++i)
{
m_mappingToSource[i] = i;
}
foreach(Column col, m_columns)
{
if (col.sortOrder == Qt::AscendingOrder)
{
ColumnSortProxyModelLessThan lt(col.column, qobject_cast<AbstractSortModel*>(sourceModel()));
std::stable_sort(m_mappingToSource.begin(), m_mappingToSource.end(), lt);
}
else
{
ColumnSortProxyModelGreaterThan gt(col.column, qobject_cast<AbstractSortModel*>(sourceModel()));
std::stable_sort(m_mappingToSource.begin(), m_mappingToSource.end(), gt);
}
}
emit layoutChanged();
emit SortChanged();
}
void ColumnSortProxyModel::SourceDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
{
for (int col = topLeft.column(); col <= bottomRight.column(); ++col)
{
if (ColumnContains(col) != -1)
{
SortModel();
return;
}
}
}
int ColumnSortProxyModel::ColumnContains(int col) const
{
for (int i = 0; i < m_columns.count(); ++i)
{
if (m_columns.at(i).column == col)
{
return i;
}
}
return -1;
}
#include <Util/moc_ColumnSortProxyModel.cpp>