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.
285 lines
7.1 KiB
C++
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>
|