diff options
Diffstat (limited to 'src/qtgroupingproxy.cpp')
| -rw-r--r-- | src/qtgroupingproxy.cpp | 1565 |
1 files changed, 708 insertions, 857 deletions
diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index 5fcb84d3..51a1517c 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -16,7 +16,6 @@ // Modifications 2013-03-27 to 2013-03-29 by Sebastian Herbord
-
#include "qtgroupingproxy.h"
#include <QDebug>
@@ -31,1038 +30,890 @@ \ingroup model-view
*/
-QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, int groupedRole, unsigned int flags , int aggregateRole)
- : QAbstractProxyModel()
- , m_rootNode( rootNode )
- , m_groupedColumn( 0 )
- , m_groupedRole( groupedRole )
- , m_aggregateRole( aggregateRole )
- , m_flags( flags )
-{
- setSourceModel( model );
+QtGroupingProxy::QtGroupingProxy(QAbstractItemModel* model, QModelIndex rootNode, int groupedColumn, int groupedRole,
+ unsigned int flags, int aggregateRole)
+ : QAbstractProxyModel(), m_rootNode(rootNode), m_groupedColumn(0), m_groupedRole(groupedRole),
+ m_aggregateRole(aggregateRole), m_flags(flags) {
+ setSourceModel(model);
- // signal proxies
- connect( sourceModel(),
- SIGNAL( dataChanged( const QModelIndex&, const QModelIndex& ) ),
- this, SLOT( modelDataChanged( const QModelIndex&, const QModelIndex& ) )
- );
- connect( sourceModel(), SIGNAL( rowsInserted( const QModelIndex&, int, int ) ),
- SLOT( modelRowsInserted( const QModelIndex &, int, int ) ) );
- connect( sourceModel(), SIGNAL(rowsAboutToBeInserted( const QModelIndex &, int ,int )),
- SLOT(modelRowsAboutToBeInserted( const QModelIndex &, int ,int )));
- connect( sourceModel(), SIGNAL( rowsRemoved( const QModelIndex&, int, int ) ),
- SLOT( modelRowsRemoved( const QModelIndex&, int, int ) ) );
- connect( sourceModel(), SIGNAL(rowsAboutToBeRemoved( const QModelIndex &, int ,int )),
- SLOT(modelRowsAboutToBeRemoved(QModelIndex,int,int)) );
- connect( sourceModel(), SIGNAL(layoutChanged()), SLOT(buildTree()) );
- connect( sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex)),
- SLOT(modelDataChanged(QModelIndex,QModelIndex)) );
- connect( sourceModel(), SIGNAL(modelReset()), this, SLOT(resetModel()) );
+ // signal proxies
+ connect(sourceModel(), SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), this,
+ SLOT(modelDataChanged(const QModelIndex&, const QModelIndex&)));
+ connect(sourceModel(), SIGNAL(rowsInserted(const QModelIndex&, int, int)),
+ SLOT(modelRowsInserted(const QModelIndex&, int, int)));
+ connect(sourceModel(), SIGNAL(rowsAboutToBeInserted(const QModelIndex&, int, int)),
+ SLOT(modelRowsAboutToBeInserted(const QModelIndex&, int, int)));
+ connect(sourceModel(), SIGNAL(rowsRemoved(const QModelIndex&, int, int)),
+ SLOT(modelRowsRemoved(const QModelIndex&, int, int)));
+ connect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(const QModelIndex&, int, int)),
+ SLOT(modelRowsAboutToBeRemoved(QModelIndex, int, int)));
+ connect(sourceModel(), SIGNAL(layoutChanged()), SLOT(buildTree()));
+ connect(sourceModel(), SIGNAL(dataChanged(QModelIndex, QModelIndex)),
+ SLOT(modelDataChanged(QModelIndex, QModelIndex)));
+ connect(sourceModel(), SIGNAL(modelReset()), this, SLOT(resetModel()));
- if( groupedColumn != -1 )
- setGroupedColumn( groupedColumn );
+ if (groupedColumn != -1)
+ setGroupedColumn(groupedColumn);
}
-QtGroupingProxy::~QtGroupingProxy()
-{
-}
+QtGroupingProxy::~QtGroupingProxy() {}
-void
-QtGroupingProxy::setGroupedColumn( int groupedColumn )
-{
- m_groupedColumn = groupedColumn;
- buildTree();
+void QtGroupingProxy::setGroupedColumn(int groupedColumn) {
+ m_groupedColumn = groupedColumn;
+ buildTree();
}
/** Maps to what groups the source row belongs by returning the data of those groups.
- *
- * @returns a list of data for the rows the argument belongs to. In common cases this list will
- * contain only one entry. An empty list means that the source item will be placed in the root of
- * this proxyModel. There is no support for hiding source items.
- *
- * Group data can be pre-loaded in the return value so it's added to the cache maintained by this
- * class. This is required if you want to have data that is not present in the source model.
- */
-QList<RowData>
-QtGroupingProxy::belongsTo( const QModelIndex &idx )
-{
- //qDebug() << __FILE__ << __FUNCTION__;
- QList<RowData> rowDataList;
+ *
+ * @returns a list of data for the rows the argument belongs to. In common cases this list will
+ * contain only one entry. An empty list means that the source item will be placed in the root of
+ * this proxyModel. There is no support for hiding source items.
+ *
+ * Group data can be pre-loaded in the return value so it's added to the cache maintained by this
+ * class. This is required if you want to have data that is not present in the source model.
+ */
+QList<RowData> QtGroupingProxy::belongsTo(const QModelIndex& idx) {
+ // qDebug() << __FILE__ << __FUNCTION__;
+ QList<RowData> rowDataList;
- //get all the data for this index from the model
- ItemData itemData = sourceModel()->itemData( idx );
- if (m_groupedRole != Qt::DisplayRole) {
- itemData[Qt::DisplayRole] = itemData[m_groupedRole];
- }
+ // get all the data for this index from the model
+ ItemData itemData = sourceModel()->itemData(idx);
+ if (m_groupedRole != Qt::DisplayRole) {
+ itemData[Qt::DisplayRole] = itemData[m_groupedRole];
+ }
- // invalid value in grouped role -> ungrouped
- if (!itemData[Qt::DisplayRole].isValid()) {
- return rowDataList;
- }
+ // invalid value in grouped role -> ungrouped
+ if (!itemData[Qt::DisplayRole].isValid()) {
+ return rowDataList;
+ }
- QMapIterator<int, QVariant> i( itemData );
- while( i.hasNext() )
- {
- i.next();
- int role = i.key();
- QVariant variant = i.value();
- // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant;
- if ( variant.type() == QVariant::List )
- {
- //a list of variants get's expanded to multiple rows
- QVariantList list = variant.toList();
- for( int i = 0; i < list.length(); i++ )
- {
- //take an existing row data or create a new one
- RowData rowData = (rowDataList.count() > i) ? rowDataList.takeAt( i )
- : RowData();
+ QMapIterator<int, QVariant> i(itemData);
+ while (i.hasNext()) {
+ i.next();
+ int role = i.key();
+ QVariant variant = i.value();
+ // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant;
+ if (variant.type() == QVariant::List) {
+ // a list of variants get's expanded to multiple rows
+ QVariantList list = variant.toList();
+ for (int i = 0; i < list.length(); i++) {
+ // take an existing row data or create a new one
+ RowData rowData = (rowDataList.count() > i) ? rowDataList.takeAt(i) : RowData();
- //we only gather data for the first column
- ItemData indexData = rowData.contains( 0 ) ? rowData.take( 0 ) : ItemData();
- indexData.insert( role, list.value( i ) );
- rowData.insert( 0, indexData );
- //for the grouped column the data should not be gathered from the children
- //this will allow filtering on the content of this column with a
- //QSortFilterProxyModel
- rowData.insert( m_groupedColumn, indexData );
- rowDataList.insert( i, rowData );
- }
- break;
- }
- else if( !variant.isNull() )
- {
- //it's just a normal item. Copy all the data and break this loop.
- RowData rowData;
- rowData.insert( 0, itemData );
- rowDataList << rowData;
- break;
+ // we only gather data for the first column
+ ItemData indexData = rowData.contains(0) ? rowData.take(0) : ItemData();
+ indexData.insert(role, list.value(i));
+ rowData.insert(0, indexData);
+ // for the grouped column the data should not be gathered from the children
+ // this will allow filtering on the content of this column with a
+ // QSortFilterProxyModel
+ rowData.insert(m_groupedColumn, indexData);
+ rowDataList.insert(i, rowData);
+ }
+ break;
+ } else if (!variant.isNull()) {
+ // it's just a normal item. Copy all the data and break this loop.
+ RowData rowData;
+ rowData.insert(0, itemData);
+ rowDataList << rowData;
+ break;
+ }
}
- }
- return rowDataList;
+ return rowDataList;
}
/* m_groupHash layout
-* key : index of the group in m_groupMaps
-* value : a QList of the original rows in sourceModel() for the children of this group
-*
-* key = -1 contains a QList of the non-grouped indexes
-*
-* TODO: sub-groups
-*/
-void
-QtGroupingProxy::buildTree()
-{
- if( !sourceModel() )
- return;
- beginResetModel();
+ * key : index of the group in m_groupMaps
+ * value : a QList of the original rows in sourceModel() for the children of this group
+ *
+ * key = -1 contains a QList of the non-grouped indexes
+ *
+ * TODO: sub-groups
+ */
+void QtGroupingProxy::buildTree() {
+ if (!sourceModel())
+ return;
+ beginResetModel();
- m_groupHash.clear();
- //don't clear the data maps since most of it will probably be needed again.
- m_parentCreateList.clear();
+ m_groupHash.clear();
+ // don't clear the data maps since most of it will probably be needed again.
+ m_parentCreateList.clear();
- int max = sourceModel()->rowCount( m_rootNode );
- //qDebug() << QString("building tree with %1 leafs.").arg( max );
- //WARNING: these have to be added in order because the addToGroups function is optimized for
- //modelRowsInserted(). Failure to do so will result in wrong data shown in the view at best.
- for( int row = 0; row < max; row++ )
- {
- QModelIndex idx = sourceModel()->index( row, m_groupedColumn, m_rootNode );
- addSourceRow( idx );
- }
- //dumpGroups();
+ int max = sourceModel()->rowCount(m_rootNode);
+ // qDebug() << QString("building tree with %1 leafs.").arg( max );
+ // WARNING: these have to be added in order because the addToGroups function is optimized for
+ // modelRowsInserted(). Failure to do so will result in wrong data shown in the view at best.
+ for (int row = 0; row < max; row++) {
+ QModelIndex idx = sourceModel()->index(row, m_groupedColumn, m_rootNode);
+ addSourceRow(idx);
+ }
+ // dumpGroups();
- if (m_flags & FLAG_NOSINGLE) {
- // awkward: flatten single-item groups as a post-processing steps.
+ if (m_flags & FLAG_NOSINGLE) {
+ // awkward: flatten single-item groups as a post-processing steps.
- int currentKey = 0;
- quint32 quint32max = std::numeric_limits<quint32>::max();
- std::vector<int> rmgroups;
+ int currentKey = 0;
+ quint32 quint32max = std::numeric_limits<quint32>::max();
+ std::vector<int> rmgroups;
- QHash<quint32, QList<int> > temp;
+ QHash<quint32, QList<int>> temp;
- for (auto iter = m_groupHash.begin(); iter != m_groupHash.end(); ++iter) {
- if ((iter.key() == quint32max) ||
- (iter->count() < 2)) {
- temp[quint32max].append(iter.value());
- if (iter.key() != quint32max) {
- rmgroups.push_back(iter.key());
+ for (auto iter = m_groupHash.begin(); iter != m_groupHash.end(); ++iter) {
+ if ((iter.key() == quint32max) || (iter->count() < 2)) {
+ temp[quint32max].append(iter.value());
+ if (iter.key() != quint32max) {
+ rmgroups.push_back(iter.key());
+ }
+ } else {
+ temp[currentKey++] = *iter;
+ }
}
- } else {
- temp[currentKey++] = *iter;
- }
- }
- m_groupHash = temp;
+ m_groupHash = temp;
- // second loop is necessary because qt containers can't be iterated from end to front
- // and removing by index from begin to end is ugly
- std::sort(rmgroups.begin(), rmgroups.end(), [] (int lhs, int rhs) { return rhs < lhs; });
- for (auto iter = rmgroups.begin(); iter != rmgroups.end(); ++iter) {
- m_groupMaps.removeAt(*iter);
+ // second loop is necessary because qt containers can't be iterated from end to front
+ // and removing by index from begin to end is ugly
+ std::sort(rmgroups.begin(), rmgroups.end(), [](int lhs, int rhs) { return rhs < lhs; });
+ for (auto iter = rmgroups.begin(); iter != rmgroups.end(); ++iter) {
+ m_groupMaps.removeAt(*iter);
+ }
}
- }
- endResetModel();
- // restore expand-state
- for( int row = 0; row < rowCount(); row++ ) {
- QModelIndex idx = index( row, 0, QModelIndex() );
- if (m_expandedItems.contains(idx.data(Qt::UserRole).toString())) {
- emit expandItem(idx);
+ endResetModel();
+ // restore expand-state
+ for (int row = 0; row < rowCount(); row++) {
+ QModelIndex idx = index(row, 0, QModelIndex());
+ if (m_expandedItems.contains(idx.data(Qt::UserRole).toString())) {
+ emit expandItem(idx);
+ }
}
- }
}
-QList<int>
-QtGroupingProxy::addSourceRow( const QModelIndex &idx )
-{
- QList<int> updatedGroups;
- QList<RowData> groupData = belongsTo( idx );
+QList<int> QtGroupingProxy::addSourceRow(const QModelIndex& idx) {
+ QList<int> updatedGroups;
+ QList<RowData> groupData = belongsTo(idx);
- //an empty list here means it's supposed to go in root.
- if( groupData.isEmpty() )
- {
- updatedGroups << -1;
- if( !m_groupHash.keys().contains( std::numeric_limits<quint32>::max() ) )
- m_groupHash.insert( std::numeric_limits<quint32>::max(), QList<int>() ); //add an empty placeholder
- }
+ // an empty list here means it's supposed to go in root.
+ if (groupData.isEmpty()) {
+ updatedGroups << -1;
+ if (!m_groupHash.keys().contains(std::numeric_limits<quint32>::max()))
+ m_groupHash.insert(std::numeric_limits<quint32>::max(), QList<int>()); // add an empty placeholder
+ }
- //an item can be in multiple groups
- foreach( RowData data, groupData )
- {
- int updatedGroup = -1;
- if( !data.isEmpty() )
- {
- // qDebug() << QString("index %1 belongs to group %2").arg( row )
- // .arg( data[0][Qt::DisplayRole].toString() );
+ // an item can be in multiple groups
+ foreach (RowData data, groupData) {
+ int updatedGroup = -1;
+ if (!data.isEmpty()) {
+ // qDebug() << QString("index %1 belongs to group %2").arg( row )
+ // .arg( data[0][Qt::DisplayRole].toString() );
- foreach( const RowData &cachedData, m_groupMaps )
- {
- //when this matches the index belongs to an existing group
- if( data[0][Qt::DisplayRole] == cachedData[0][Qt::DisplayRole] )
- {
- data = cachedData;
- break;
- }
- }
-
- updatedGroup = m_groupMaps.indexOf( data );
- //-1 means not found
- if( updatedGroup == -1 )
- {
- //new groups are added to the end of the existing list
- m_groupMaps << data;
- updatedGroup = m_groupMaps.count() - 1;
- }
+ foreach (const RowData& cachedData, m_groupMaps) {
+ // when this matches the index belongs to an existing group
+ if (data[0][Qt::DisplayRole] == cachedData[0][Qt::DisplayRole]) {
+ data = cachedData;
+ break;
+ }
+ }
- if( !m_groupHash.keys().contains( updatedGroup ) )
- m_groupHash.insert( updatedGroup, QList<int>() ); //add an empty placeholder
- }
+ updatedGroup = m_groupMaps.indexOf(data);
+ //-1 means not found
+ if (updatedGroup == -1) {
+ // new groups are added to the end of the existing list
+ m_groupMaps << data;
+ updatedGroup = m_groupMaps.count() - 1;
+ }
- if( !updatedGroups.contains( updatedGroup ) )
- updatedGroups << updatedGroup;
- }
+ if (!m_groupHash.keys().contains(updatedGroup))
+ m_groupHash.insert(updatedGroup, QList<int>()); // add an empty placeholder
+ }
- //update m_groupHash to the new source-model layout (one row added)
- QMutableHashIterator<quint32, QList<int> > i( m_groupHash );
- while( i.hasNext() )
- {
- i.next();
- QList<int> &groupList = i.value();
- int insertedProxyRow = groupList.count();
- for( ; insertedProxyRow > 0 ; insertedProxyRow-- )
- {
- int &rowValue = groupList[insertedProxyRow-1];
- if( idx.row() <= rowValue )
- {
- //increment the rows that come after the new row since they moved one place up.
- rowValue++;
- }
- else
- {
- break;
- }
+ if (!updatedGroups.contains(updatedGroup))
+ updatedGroups << updatedGroup;
}
- if( updatedGroups.contains( i.key() ) )
- {
- //the row needs to be added to this group
- groupList.insert( insertedProxyRow, idx.row() );
+ // update m_groupHash to the new source-model layout (one row added)
+ QMutableHashIterator<quint32, QList<int>> i(m_groupHash);
+ while (i.hasNext()) {
+ i.next();
+ QList<int>& groupList = i.value();
+ int insertedProxyRow = groupList.count();
+ for (; insertedProxyRow > 0; insertedProxyRow--) {
+ int& rowValue = groupList[insertedProxyRow - 1];
+ if (idx.row() <= rowValue) {
+ // increment the rows that come after the new row since they moved one place up.
+ rowValue++;
+ } else {
+ break;
+ }
+ }
+
+ if (updatedGroups.contains(i.key())) {
+ // the row needs to be added to this group
+ groupList.insert(insertedProxyRow, idx.row());
+ }
}
- }
- return updatedGroups;
+ return updatedGroups;
}
/** Each ModelIndex has in it's internalId a position in the parentCreateList.
- * struct ParentCreate are the instructions to recreate the parent index.
- * It contains the proxy row number of the parent and the postion in this list of the grandfather.
- * This function creates the ParentCreate structs and saves them in a list.
- */
-int
-QtGroupingProxy::indexOfParentCreate( const QModelIndex &parent ) const
-{
- if( !parent.isValid() )
- return -1;
+ * struct ParentCreate are the instructions to recreate the parent index.
+ * It contains the proxy row number of the parent and the postion in this list of the grandfather.
+ * This function creates the ParentCreate structs and saves them in a list.
+ */
+int QtGroupingProxy::indexOfParentCreate(const QModelIndex& parent) const {
+ if (!parent.isValid())
+ return -1;
- struct ParentCreate pc;
- for( int i = 0 ; i < m_parentCreateList.size() ; i++ )
- {
- pc = m_parentCreateList[i];
- if( pc.parentCreateIndex == parent.internalId() && pc.row == parent.row() )
- return i;
- }
- //there is no parentCreate yet for this index, so let's create one.
- pc.parentCreateIndex = parent.internalId();
- pc.row = parent.row();
- m_parentCreateList << pc;
+ struct ParentCreate pc;
+ for (int i = 0; i < m_parentCreateList.size(); i++) {
+ pc = m_parentCreateList[i];
+ if (pc.parentCreateIndex == parent.internalId() && pc.row == parent.row())
+ return i;
+ }
+ // there is no parentCreate yet for this index, so let's create one.
+ pc.parentCreateIndex = parent.internalId();
+ pc.row = parent.row();
+ m_parentCreateList << pc;
- //dumpParentCreateList();
- // qDebug() << QString( "m_parentCreateList: (%1)" ).arg( m_parentCreateList.size() );
- // for( int i = 0 ; i < m_parentCreateList.size() ; i++ )
- // {
- // qDebug() << i << " : " << m_parentCreateList[i].parentCreateIndex <<
- // " | " << m_parentCreateList[i].row;
- // }
+ // dumpParentCreateList();
+ // qDebug() << QString( "m_parentCreateList: (%1)" ).arg( m_parentCreateList.size() );
+ // for( int i = 0 ; i < m_parentCreateList.size() ; i++ )
+ // {
+ // qDebug() << i << " : " << m_parentCreateList[i].parentCreateIndex <<
+ // " | " << m_parentCreateList[i].row;
+ // }
- return m_parentCreateList.size() - 1;
+ return m_parentCreateList.size() - 1;
}
-QModelIndex
-QtGroupingProxy::index( int row, int column, const QModelIndex &parent ) const
-{
- // qDebug() << "index requested for: (" << row << "," << column << "), " << parent;
- if( !hasIndex(row, column, parent) ) {
- return QModelIndex();
- }
+QModelIndex QtGroupingProxy::index(int row, int column, const QModelIndex& parent) const {
+ // qDebug() << "index requested for: (" << row << "," << column << "), " << parent;
+ if (!hasIndex(row, column, parent)) {
+ return QModelIndex();
+ }
- if( parent.column() > 0 ) {
- return QModelIndex();
- }
+ if (parent.column() > 0) {
+ return QModelIndex();
+ }
- /* We save the instructions to make the parent of the index in a struct.
+ /* We save the instructions to make the parent of the index in a struct.
* The place of the struct in the list is stored in the internalId
*/
- int parentCreateIndex = indexOfParentCreate( parent );
+ int parentCreateIndex = indexOfParentCreate(parent);
- return createIndex( row, column, parentCreateIndex );
+ return createIndex(row, column, parentCreateIndex);
}
-QModelIndex
-QtGroupingProxy::parent( const QModelIndex &index ) const
-{
- //qDebug() << "parent: " << index;
- if( !index.isValid() )
- return QModelIndex();
+QModelIndex QtGroupingProxy::parent(const QModelIndex& index) const {
+ // qDebug() << "parent: " << index;
+ if (!index.isValid())
+ return QModelIndex();
- int parentCreateIndex = index.internalId();
- //qDebug() << "parentCreateIndex: " << parentCreateIndex;
- if( parentCreateIndex == -1 || parentCreateIndex >= m_parentCreateList.count() )
- return QModelIndex();
+ int parentCreateIndex = index.internalId();
+ // qDebug() << "parentCreateIndex: " << parentCreateIndex;
+ if (parentCreateIndex == -1 || parentCreateIndex >= m_parentCreateList.count())
+ return QModelIndex();
- struct ParentCreate pc = m_parentCreateList[parentCreateIndex];
- //qDebug() << "parentCreate: (" << pc.parentCreateIndex << "," << pc.row << ")";
- //only items at column 0 have children
- return createIndex( pc.row, 0, pc.parentCreateIndex );
+ struct ParentCreate pc = m_parentCreateList[parentCreateIndex];
+ // qDebug() << "parentCreate: (" << pc.parentCreateIndex << "," << pc.row << ")";
+ // only items at column 0 have children
+ return createIndex(pc.row, 0, pc.parentCreateIndex);
}
-int
-QtGroupingProxy::rowCount( const QModelIndex &index ) const
-{
- //qDebug() << "rowCount: " << index;
- if( !index.isValid() )
- {
- //the number of top level groups + the number of non-grouped items
- int rows = m_groupMaps.count() + m_groupHash.value( std::numeric_limits<quint32>::max() ).count();
- //qDebug() << rows << " in root group";
- return rows;
- }
+int QtGroupingProxy::rowCount(const QModelIndex& index) const {
+ // qDebug() << "rowCount: " << index;
+ if (!index.isValid()) {
+ // the number of top level groups + the number of non-grouped items
+ int rows = m_groupMaps.count() + m_groupHash.value(std::numeric_limits<quint32>::max()).count();
+ // qDebug() << rows << " in root group";
+ return rows;
+ }
- //TODO:group in group support.
- if( isGroup( index ) )
- {
- qint64 groupIndex = index.row();
- int rows = m_groupHash.value( groupIndex ).count();
- //qDebug() << rows << " in group " << m_groupMaps[groupIndex];
- return rows;
- } else {
- QModelIndex originalIndex = mapToSource( index );
- int rowCount = sourceModel()->rowCount( originalIndex );
- //qDebug() << "original item: rowCount == " << rowCount;
- return rowCount;
- }
+ // TODO:group in group support.
+ if (isGroup(index)) {
+ qint64 groupIndex = index.row();
+ int rows = m_groupHash.value(groupIndex).count();
+ // qDebug() << rows << " in group " << m_groupMaps[groupIndex];
+ return rows;
+ } else {
+ QModelIndex originalIndex = mapToSource(index);
+ int rowCount = sourceModel()->rowCount(originalIndex);
+ // qDebug() << "original item: rowCount == " << rowCount;
+ return rowCount;
+ }
}
-int
-QtGroupingProxy::columnCount( const QModelIndex &index ) const
-{
- if( !index.isValid() )
- return sourceModel()->columnCount( m_rootNode );
+int QtGroupingProxy::columnCount(const QModelIndex& index) const {
+ if (!index.isValid())
+ return sourceModel()->columnCount(m_rootNode);
- if( index.column() != 0 )
- return 0;
+ if (index.column() != 0)
+ return 0;
- return sourceModel()->columnCount( mapToSource( index ) );
+ return sourceModel()->columnCount(mapToSource(index));
}
+static bool variantLess(const QVariant& LHS, const QVariant& RHS) {
+ if ((LHS.type() == RHS.type()) && ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) {
+ return LHS.toInt() < RHS.toInt();
+ }
-static bool variantLess(const QVariant &LHS, const QVariant &RHS)
-{
- if ((LHS.type() == RHS.type()) &&
- ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) {
- return LHS.toInt() < RHS.toInt();
- }
-
- // this should always work (comparing empty strings in the worst case) but
- // the results may be wrong
- return LHS.toString() < RHS.toString();
+ // this should always work (comparing empty strings in the worst case) but
+ // the results may be wrong
+ return LHS.toString() < RHS.toString();
}
-
-static QVariant variantMax(const QVariantList &variants)
-{
- QVariant result = variants.first();
- foreach (const QVariant &iter, variants) {
- if (variantLess(result, iter)) {
- result = iter;
+static QVariant variantMax(const QVariantList& variants) {
+ QVariant result = variants.first();
+ foreach (const QVariant& iter, variants) {
+ if (variantLess(result, iter)) {
+ result = iter;
+ }
}
- }
- return result;
+ return result;
}
-
-static QVariant variantMin(const QVariantList &variants)
-{
- QVariant result = variants.first();
- foreach (const QVariant &iter, variants) {
- if (variantLess(iter, result)) {
- result = iter;
+static QVariant variantMin(const QVariantList& variants) {
+ QVariant result = variants.first();
+ foreach (const QVariant& iter, variants) {
+ if (variantLess(iter, result)) {
+ result = iter;
+ }
}
- }
- return result;
+ return result;
}
-
-QVariant
-QtGroupingProxy::data( const QModelIndex &index, int role ) const
-{
- if( !index.isValid() )
- return QVariant();
- // qDebug() << __FUNCTION__ << index << " role: " << role;
- int row = index.row();
- int column = index.column();
- if( isGroup( index ) )
- {
- if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) {
- switch (role) {
- case Qt::ForegroundRole: {
- return QBrush(Qt::gray);
- } break;
- case Qt::FontRole: {
- QFont font(m_groupMaps[row][column].value(Qt::FontRole).value<QFont>());
- font.setItalic(true);
- return font;
- } break;
- case Qt::TextAlignmentRole: {
- return Qt::AlignHCenter;
- } break;
- case Qt::UserRole: {
- return m_groupMaps[row][column].value( Qt::DisplayRole ).toString();
- } break;
- case Qt::CheckStateRole: {
- if (column != 0) return QVariant();
- int childCount = m_groupHash.value( row ).count();
- int checked = 0;
- QModelIndex parentIndex = this->index( row, 0, index.parent() );
- for( int childRow = 0; childRow < childCount; ++childRow )
- {
- QModelIndex childIndex = this->index( childRow, 0, parentIndex );
- QVariant data = mapToSource( childIndex ).data( Qt::CheckStateRole );
- if (data.toInt() == 2) ++checked;
+QVariant QtGroupingProxy::data(const QModelIndex& index, int role) const {
+ if (!index.isValid())
+ return QVariant();
+ // qDebug() << __FUNCTION__ << index << " role: " << role;
+ int row = index.row();
+ int column = index.column();
+ if (isGroup(index)) {
+ if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) {
+ switch (role) {
+ case Qt::ForegroundRole: {
+ return QBrush(Qt::gray);
+ } break;
+ case Qt::FontRole: {
+ QFont font(m_groupMaps[row][column].value(Qt::FontRole).value<QFont>());
+ font.setItalic(true);
+ return font;
+ } break;
+ case Qt::TextAlignmentRole: {
+ return Qt::AlignHCenter;
+ } break;
+ case Qt::UserRole: {
+ return m_groupMaps[row][column].value(Qt::DisplayRole).toString();
+ } break;
+ case Qt::CheckStateRole: {
+ if (column != 0)
+ return QVariant();
+ int childCount = m_groupHash.value(row).count();
+ int checked = 0;
+ QModelIndex parentIndex = this->index(row, 0, index.parent());
+ for (int childRow = 0; childRow < childCount; ++childRow) {
+ QModelIndex childIndex = this->index(childRow, 0, parentIndex);
+ QVariant data = mapToSource(childIndex).data(Qt::CheckStateRole);
+ if (data.toInt() == 2)
+ ++checked;
+ }
+ if (checked == childCount)
+ return Qt::Checked;
+ else if (checked == 0)
+ return Qt::Unchecked;
+ else
+ return Qt::PartiallyChecked;
+ } break;
+ default: {
+ QModelIndex parentIndex = this->index(row, 0, index.parent());
+ if (m_groupHash.value(row).count() > 0) {
+ return this->index(0, column, parentIndex).data(role);
+ } else {
+ return QVariant();
+ }
+ // return m_groupMaps[row][column].value( role );
+ } break;
}
- if (checked == childCount) return Qt::Checked;
- else if (checked == 0) return Qt::Unchecked;
- else return Qt::PartiallyChecked;
- } break;
- default: {
- QModelIndex parentIndex = this->index( row, 0, index.parent() );
- if (m_groupHash.value( row ).count() > 0) {
- return this->index(0, column, parentIndex).data(role);
+ }
+
+ // qDebug() << __FUNCTION__ << "is a group";
+ // use cached or precalculated data
+ if (m_groupMaps[row][column].contains(Qt::DisplayRole)) {
+ // qDebug() << "Using cached data for " << row << "x" << column << ": " <<
+ // m_groupMaps[row][column].value(Qt::DisplayRole).toString();
+ if ((m_flags & FLAG_NOGROUPNAME) != 0) {
+ QModelIndex parentIndex = this->index(row, 0, index.parent());
+ QModelIndex childIndex = this->index(0, column, parentIndex);
+ return childIndex.data(role).toString();
} else {
- return QVariant();
+ return m_groupMaps[row][column].value(role).toString();
}
- // return m_groupMaps[row][column].value( role );
- } break;
- }
- }
-
- //qDebug() << __FUNCTION__ << "is a group";
- //use cached or precalculated data
- if( m_groupMaps[row][column].contains( Qt::DisplayRole ) )
- {
- // qDebug() << "Using cached data for " << row << "x" << column << ": " << m_groupMaps[row][column].value(Qt::DisplayRole).toString();
- if ((m_flags & FLAG_NOGROUPNAME) != 0) {
- QModelIndex parentIndex = this->index( row, 0, index.parent() );
- QModelIndex childIndex = this->index( 0, column, parentIndex );
- return childIndex.data(role).toString();
- } else {
- return m_groupMaps[row][column].value( role ).toString();
- }
- }
+ }
- //for column 0 we gather data from the grouped column instead
- if( column == 0 )
- column = m_groupedColumn;
+ // for column 0 we gather data from the grouped column instead
+ if (column == 0)
+ column = m_groupedColumn;
- //map all data from children to columns of group to allow grouping one level up
- QVariantList variantsOfChildren;
- int childCount = m_groupHash.value( row ).count();
- if( childCount == 0 )
- return QVariant();
+ // map all data from children to columns of group to allow grouping one level up
+ QVariantList variantsOfChildren;
+ int childCount = m_groupHash.value(row).count();
+ if (childCount == 0)
+ return QVariant();
- int function = AGGR_NONE;
- if (m_aggregateRole >= Qt::UserRole) {
- QModelIndex parentIndex = this->index( row, 0, index.parent() );
- QModelIndex childIndex = this->index( 0, column, parentIndex );
- function = mapToSource(childIndex).data(m_aggregateRole).toInt();
- }
+ int function = AGGR_NONE;
+ if (m_aggregateRole >= Qt::UserRole) {
+ QModelIndex parentIndex = this->index(row, 0, index.parent());
+ QModelIndex childIndex = this->index(0, column, parentIndex);
+ function = mapToSource(childIndex).data(m_aggregateRole).toInt();
+ }
- //qDebug() << __FUNCTION__ << "childCount: " << childCount;
- //Need a parentIndex with column == 0 because only those have children.
- QModelIndex parentIndex = this->index( row, 0, index.parent() );
- for( int childRow = 0; childRow < childCount; childRow++ )
- {
- QModelIndex childIndex = this->index( childRow, column, parentIndex );
- QVariant data = mapToSource( childIndex ).data( role );
- //qDebug() << __FUNCTION__ << data << QVariant::typeToName(data.type());
- if( data.isValid() && !variantsOfChildren.contains( data ) )
- variantsOfChildren << data;
- }
- //qDebug() << "gathered this data from children: " << variantsOfChildren;
- //saving in cache
- ItemData roleMap = m_groupMaps[row].value( column );
- foreach( const QVariant &variant, variantsOfChildren )
- {
- if( roleMap[ role ] != variant ) {
- roleMap.insert( role, variantsOfChildren );
- }
- }
+ // qDebug() << __FUNCTION__ << "childCount: " << childCount;
+ // Need a parentIndex with column == 0 because only those have children.
+ QModelIndex parentIndex = this->index(row, 0, index.parent());
+ for (int childRow = 0; childRow < childCount; childRow++) {
+ QModelIndex childIndex = this->index(childRow, column, parentIndex);
+ QVariant data = mapToSource(childIndex).data(role);
+ // qDebug() << __FUNCTION__ << data << QVariant::typeToName(data.type());
+ if (data.isValid() && !variantsOfChildren.contains(data))
+ variantsOfChildren << data;
+ }
+ // qDebug() << "gathered this data from children: " << variantsOfChildren;
+ // saving in cache
+ ItemData roleMap = m_groupMaps[row].value(column);
+ foreach (const QVariant& variant, variantsOfChildren) {
+ if (roleMap[role] != variant) {
+ roleMap.insert(role, variantsOfChildren);
+ }
+ }
- //qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role];
+ // qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role];
- if( variantsOfChildren.count() == 0 )
- return QVariant();
+ if (variantsOfChildren.count() == 0)
+ return QVariant();
- //only one unique variant? No need to return a list
- switch (function) {
- case AGGR_EMPTY: return QVariant();
- case AGGR_FIRST: return variantsOfChildren.first();
- case AGGR_MAX: return variantMax(variantsOfChildren);
- case AGGR_MIN: return variantMin(variantsOfChildren);
- default: {
- if( variantsOfChildren.count() == 1 )
+ // only one unique variant? No need to return a list
+ switch (function) {
+ case AGGR_EMPTY:
+ return QVariant();
+ case AGGR_FIRST:
return variantsOfChildren.first();
+ case AGGR_MAX:
+ return variantMax(variantsOfChildren);
+ case AGGR_MIN:
+ return variantMin(variantsOfChildren);
+ default: {
+ if (variantsOfChildren.count() == 1)
+ return variantsOfChildren.first();
- return variantsOfChildren;
+ return variantsOfChildren;
} break;
+ }
}
- }
- return mapToSource( index ).data( role );
+ return mapToSource(index).data(role);
}
-bool
-QtGroupingProxy::setData( const QModelIndex &idx, const QVariant &value, int role )
-{
- if( !idx.isValid() )
- return false;
+bool QtGroupingProxy::setData(const QModelIndex& idx, const QVariant& value, int role) {
+ if (!idx.isValid())
+ return false;
- //no need to set data to exactly the same value
- if( idx.data( role ) == value )
- return false;
+ // no need to set data to exactly the same value
+ if (idx.data(role) == value)
+ return false;
- if( isGroup( idx ) )
- {
- ItemData columnData = m_groupMaps[idx.row()][idx.column()];
+ if (isGroup(idx)) {
+ ItemData columnData = m_groupMaps[idx.row()][idx.column()];
- columnData.insert( role, value );
- //QItemDelegate will always use Qt::EditRole
- if( role == Qt::EditRole )
- columnData.insert( Qt::DisplayRole, value );
+ columnData.insert(role, value);
+ // QItemDelegate will always use Qt::EditRole
+ if (role == Qt::EditRole)
+ columnData.insert(Qt::DisplayRole, value);
- //and make sure it's stored in the map
- m_groupMaps[idx.row()].insert( idx.column(), columnData );
+ // and make sure it's stored in the map
+ m_groupMaps[idx.row()].insert(idx.column(), columnData);
- int columnToChange = idx.column() ? idx.column() : m_groupedColumn;
- foreach( int originalRow, m_groupHash.value( idx.row() ) )
- {
- QModelIndex childIdx = sourceModel()->index( originalRow, columnToChange,
- m_rootNode );
- if( childIdx.isValid() )
- sourceModel()->setData( childIdx, value, role );
- }
- //TODO: we might need to reload the data from the children at this point
+ int columnToChange = idx.column() ? idx.column() : m_groupedColumn;
+ foreach (int originalRow, m_groupHash.value(idx.row())) {
+ QModelIndex childIdx = sourceModel()->index(originalRow, columnToChange, m_rootNode);
+ if (childIdx.isValid())
+ sourceModel()->setData(childIdx, value, role);
+ }
+ // TODO: we might need to reload the data from the children at this point
- emit dataChanged( idx, idx );
- return true;
- }
+ emit dataChanged(idx, idx);
+ return true;
+ }
- return sourceModel()->setData( mapToSource( idx ), value, role );
+ return sourceModel()->setData(mapToSource(idx), value, role);
}
-bool
-QtGroupingProxy::isGroup( const QModelIndex &index ) const
-{
- int parentCreateIndex = index.internalId();
- if( parentCreateIndex == -1 && index.row() < m_groupMaps.count() )
- return true;
- return false;
+bool QtGroupingProxy::isGroup(const QModelIndex& index) const {
+ int parentCreateIndex = index.internalId();
+ if (parentCreateIndex == -1 && index.row() < m_groupMaps.count())
+ return true;
+ return false;
}
-QModelIndex
-QtGroupingProxy::mapToSource( const QModelIndex &index ) const
-{
- //qDebug() << "mapToSource: " << index;
- if( !index.isValid() ) {
- return m_rootNode;
- }
+QModelIndex QtGroupingProxy::mapToSource(const QModelIndex& index) const {
+ // qDebug() << "mapToSource: " << index;
+ if (!index.isValid()) {
+ return m_rootNode;
+ }
- if( isGroup( index ) )
- {
- //qDebug() << "is a group: " << index.data( Qt::DisplayRole ).toString();
- return m_rootNode;
- }
+ if (isGroup(index)) {
+ // qDebug() << "is a group: " << index.data( Qt::DisplayRole ).toString();
+ return m_rootNode;
+ }
- QModelIndex proxyParent = index.parent();
- //qDebug() << "parent: " << proxyParent;
- QModelIndex originalParent = mapToSource( proxyParent );
- //qDebug() << "originalParent: " << originalParent;
- int originalRow = index.row();
- if( originalParent == m_rootNode )
- {
- int indexInGroup = index.row();
- if( !proxyParent.isValid() )
- indexInGroup -= m_groupMaps.count();
- //qDebug() << "indexInGroup" << indexInGroup;
- QList<int> childRows = m_groupHash.value( proxyParent.row() );
- if( childRows.isEmpty() || indexInGroup >= childRows.count() || indexInGroup < 0 )
- return QModelIndex();
+ QModelIndex proxyParent = index.parent();
+ // qDebug() << "parent: " << proxyParent;
+ QModelIndex originalParent = mapToSource(proxyParent);
+ // qDebug() << "originalParent: " << originalParent;
+ int originalRow = index.row();
+ if (originalParent == m_rootNode) {
+ int indexInGroup = index.row();
+ if (!proxyParent.isValid())
+ indexInGroup -= m_groupMaps.count();
+ // qDebug() << "indexInGroup" << indexInGroup;
+ QList<int> childRows = m_groupHash.value(proxyParent.row());
+ if (childRows.isEmpty() || indexInGroup >= childRows.count() || indexInGroup < 0)
+ return QModelIndex();
- originalRow = childRows.at( indexInGroup );
- //qDebug() << "originalRow: " << originalRow;
- }
- return sourceModel()->index( originalRow, index.column(), originalParent );
+ originalRow = childRows.at(indexInGroup);
+ // qDebug() << "originalRow: " << originalRow;
+ }
+ return sourceModel()->index(originalRow, index.column(), originalParent);
}
-QModelIndexList
-QtGroupingProxy::mapToSource( const QModelIndexList& list ) const
-{
- QModelIndexList originalList;
- foreach( const QModelIndex &index, list )
- {
- QModelIndex originalIndex = mapToSource( index );
- if( originalIndex.isValid() )
- originalList << originalIndex;
- }
- return originalList;
+QModelIndexList QtGroupingProxy::mapToSource(const QModelIndexList& list) const {
+ QModelIndexList originalList;
+ foreach (const QModelIndex& index, list) {
+ QModelIndex originalIndex = mapToSource(index);
+ if (originalIndex.isValid())
+ originalList << originalIndex;
+ }
+ return originalList;
}
-QModelIndex
-QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const
-{
- if( !idx.isValid() )
- return QModelIndex();
+QModelIndex QtGroupingProxy::mapFromSource(const QModelIndex& idx) const {
+ if (!idx.isValid())
+ return QModelIndex();
- QModelIndex proxyParent;
- QModelIndex sourceParent = idx.parent();
- //qDebug() << "sourceParent: " << sourceParent;
- int proxyRow = idx.row();
- int sourceRow = idx.row();
+ QModelIndex proxyParent;
+ QModelIndex sourceParent = idx.parent();
+ // qDebug() << "sourceParent: " << sourceParent;
+ int proxyRow = idx.row();
+ int sourceRow = idx.row();
- if( sourceParent.isValid() && ( sourceParent != m_rootNode ) )
- {
- //idx is a child of one of the items in the source model
- proxyParent = mapFromSource( sourceParent );
- }
- else
- {
- //idx is an item in the top level of the source model (child of the rootnode)
- int groupRow = -1;
- QHashIterator<quint32, QList<int> > iterator( m_groupHash );
- while( iterator.hasNext() )
- {
- iterator.next();
- if( iterator.value().contains( sourceRow ) )
- {
- groupRow = iterator.key();
- break;
- }
- }
+ if (sourceParent.isValid() && (sourceParent != m_rootNode)) {
+ // idx is a child of one of the items in the source model
+ proxyParent = mapFromSource(sourceParent);
+ } else {
+ // idx is an item in the top level of the source model (child of the rootnode)
+ int groupRow = -1;
+ QHashIterator<quint32, QList<int>> iterator(m_groupHash);
+ while (iterator.hasNext()) {
+ iterator.next();
+ if (iterator.value().contains(sourceRow)) {
+ groupRow = iterator.key();
+ break;
+ }
+ }
- if( groupRow != -1 ) //it's in a group, let's find the correct row.
- {
- proxyParent = this->index( groupRow, 0, QModelIndex() );
- proxyRow = m_groupHash.value( groupRow ).indexOf( sourceRow );
- }
- else
- {
- proxyParent = QModelIndex();
- // if the proxy item is not in a group it will be below the groups.
- int groupLength = m_groupMaps.count();
- //qDebug() << "groupNames length: " << groupLength;
- int i = m_groupHash.value( std::numeric_limits<quint32>::max() ).indexOf( sourceRow );
- //qDebug() << "index in hash: " << i;
- proxyRow = groupLength + i;
+ if (groupRow != -1) // it's in a group, let's find the correct row.
+ {
+ proxyParent = this->index(groupRow, 0, QModelIndex());
+ proxyRow = m_groupHash.value(groupRow).indexOf(sourceRow);
+ } else {
+ proxyParent = QModelIndex();
+ // if the proxy item is not in a group it will be below the groups.
+ int groupLength = m_groupMaps.count();
+ // qDebug() << "groupNames length: " << groupLength;
+ int i = m_groupHash.value(std::numeric_limits<quint32>::max()).indexOf(sourceRow);
+ // qDebug() << "index in hash: " << i;
+ proxyRow = groupLength + i;
+ }
}
- }
- //qDebug() << "proxyParent: " << proxyParent;
- //qDebug() << "proxyRow: " << proxyRow;
- return this->index( proxyRow, idx.column(), proxyParent );
+ // qDebug() << "proxyParent: " << proxyParent;
+ // qDebug() << "proxyRow: " << proxyRow;
+ return this->index(proxyRow, idx.column(), proxyParent);
}
-Qt::ItemFlags
-QtGroupingProxy::flags( const QModelIndex &idx ) const
-{
- if( !idx.isValid() )
- {
- Qt::ItemFlags rootFlags = sourceModel()->flags( m_rootNode );
- if( rootFlags.testFlag( Qt::ItemIsDropEnabled ) )
- return Qt::ItemFlags( Qt::ItemIsDropEnabled );
+Qt::ItemFlags QtGroupingProxy::flags(const QModelIndex& idx) const {
+ if (!idx.isValid()) {
+ Qt::ItemFlags rootFlags = sourceModel()->flags(m_rootNode);
+ if (rootFlags.testFlag(Qt::ItemIsDropEnabled))
+ return Qt::ItemFlags(Qt::ItemIsDropEnabled);
- return 0;
- }
- //only if the grouped column has the editable flag set allow the
- //actions leading to setData on the source (edit & drop)
- // qDebug() << idx;
- if( isGroup( idx ) )
- {
- // dumpGroups();
- Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
- //Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled);
- bool groupIsEditable = true;
+ return 0;
+ }
+ // only if the grouped column has the editable flag set allow the
+ // actions leading to setData on the source (edit & drop)
+ // qDebug() << idx;
+ if (isGroup(idx)) {
+ // dumpGroups();
+ Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
+ // Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled);
+ bool groupIsEditable = true;
- if (idx.column() == 0) {
- bool checkable = true;
- foreach ( int originalRow, m_groupHash.value( idx.row() ) )
- {
- QModelIndex originalIdx = sourceModel()->index( originalRow, 0,
- m_rootNode.parent() );
- if ( (originalIdx.flags() & Qt::ItemIsUserCheckable) == 0 )
- {
- qDebug("row %d is not checkable", originalRow);
- checkable = false;
- }
- }
+ if (idx.column() == 0) {
+ bool checkable = true;
+ foreach (int originalRow, m_groupHash.value(idx.row())) {
+ QModelIndex originalIdx = sourceModel()->index(originalRow, 0, m_rootNode.parent());
+ if ((originalIdx.flags() & Qt::ItemIsUserCheckable) == 0) {
+ qDebug("row %d is not checkable", originalRow);
+ checkable = false;
+ }
+ }
- if ( checkable ) {
- defaultFlags |= Qt::ItemIsUserCheckable;
- }
- }
+ if (checkable) {
+ defaultFlags |= Qt::ItemIsUserCheckable;
+ }
+ }
- //it's possible to have empty groups
- if( m_groupHash.value( idx.row() ).count() == 0 )
- {
- //check the flags of this column with the root node
- QModelIndex originalRootNode = sourceModel()->index( m_rootNode.row(), m_groupedColumn,
- m_rootNode.parent() );
- groupIsEditable = originalRootNode.flags().testFlag( Qt::ItemIsEditable );
- }
- else
- {
- foreach( int originalRow, m_groupHash.value( idx.row() ) )
- {
- QModelIndex originalIdx = sourceModel()->index( originalRow, m_groupedColumn,
- m_rootNode );
+ // it's possible to have empty groups
+ if (m_groupHash.value(idx.row()).count() == 0) {
+ // check the flags of this column with the root node
+ QModelIndex originalRootNode = sourceModel()->index(m_rootNode.row(), m_groupedColumn, m_rootNode.parent());
+ groupIsEditable = originalRootNode.flags().testFlag(Qt::ItemIsEditable);
+ } else {
+ foreach (int originalRow, m_groupHash.value(idx.row())) {
+ QModelIndex originalIdx = sourceModel()->index(originalRow, m_groupedColumn, m_rootNode);
- groupIsEditable = groupIsEditable
- ? originalIdx.flags().testFlag( Qt::ItemIsEditable )
- : false;
- if( !groupIsEditable ) //all children need to have an editable grouped column
- break;
- }
+ groupIsEditable = groupIsEditable ? originalIdx.flags().testFlag(Qt::ItemIsEditable) : false;
+ if (!groupIsEditable) // all children need to have an editable grouped column
+ break;
+ }
+ }
+ if (groupIsEditable)
+ return (defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled);
+ return defaultFlags;
}
- if( groupIsEditable )
- return ( defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled );
- return defaultFlags;
- }
- QModelIndex originalIdx = mapToSource( idx );
- Qt::ItemFlags originalItemFlags = sourceModel()->flags( originalIdx );
+ QModelIndex originalIdx = mapToSource(idx);
+ Qt::ItemFlags originalItemFlags = sourceModel()->flags(originalIdx);
- //check the source model to see if the grouped column is editable;
- QModelIndex groupedColumnIndex =
- sourceModel()->index( originalIdx.row(), m_groupedColumn, originalIdx.parent() );
- bool groupIsEditable = sourceModel()->flags( groupedColumnIndex ).testFlag( Qt::ItemIsEditable );
+ // check the source model to see if the grouped column is editable;
+ QModelIndex groupedColumnIndex = sourceModel()->index(originalIdx.row(), m_groupedColumn, originalIdx.parent());
+ bool groupIsEditable = sourceModel()->flags(groupedColumnIndex).testFlag(Qt::ItemIsEditable);
- if( groupIsEditable )
- return originalItemFlags | Qt::ItemIsDragEnabled;
- return originalItemFlags;
+ if (groupIsEditable)
+ return originalItemFlags | Qt::ItemIsDragEnabled;
+ return originalItemFlags;
}
-QVariant
-QtGroupingProxy::headerData( int section, Qt::Orientation orientation, int role ) const
-{
- return sourceModel()->headerData( section, orientation, role );
+QVariant QtGroupingProxy::headerData(int section, Qt::Orientation orientation, int role) const {
+ return sourceModel()->headerData(section, orientation, role);
}
-bool
-QtGroupingProxy::canFetchMore( const QModelIndex &parent ) const
-{
- if( !parent.isValid() )
- return false;
+bool QtGroupingProxy::canFetchMore(const QModelIndex& parent) const {
+ if (!parent.isValid())
+ return false;
- if( isGroup( parent ) )
- return false;
+ if (isGroup(parent))
+ return false;
- return sourceModel()->canFetchMore( mapToSource( parent ) );
+ return sourceModel()->canFetchMore(mapToSource(parent));
}
-void
-QtGroupingProxy::fetchMore ( const QModelIndex & parent )
-{
- if( !parent.isValid() )
- return;
+void QtGroupingProxy::fetchMore(const QModelIndex& parent) {
+ if (!parent.isValid())
+ return;
- if( isGroup( parent ) )
- return;
+ if (isGroup(parent))
+ return;
- return sourceModel()->fetchMore( mapToSource( parent ) );
+ return sourceModel()->fetchMore(mapToSource(parent));
}
-QModelIndex
-QtGroupingProxy::addEmptyGroup( const RowData &data )
-{
- int newRow = m_groupMaps.count();
- beginInsertRows( QModelIndex(), newRow, newRow );
- m_groupMaps << data;
- endInsertRows();
- return index( newRow, 0, QModelIndex() );
+QModelIndex QtGroupingProxy::addEmptyGroup(const RowData& data) {
+ int newRow = m_groupMaps.count();
+ beginInsertRows(QModelIndex(), newRow, newRow);
+ m_groupMaps << data;
+ endInsertRows();
+ return index(newRow, 0, QModelIndex());
}
-bool
-QtGroupingProxy::removeGroup( const QModelIndex &idx )
-{
- beginRemoveRows( idx.parent(), idx.row(), idx.row() );
- m_groupHash.remove( idx.row() );
- m_groupMaps.removeAt( idx.row() );
- m_parentCreateList.removeAt( idx.internalId() );
- endRemoveRows();
+bool QtGroupingProxy::removeGroup(const QModelIndex& idx) {
+ beginRemoveRows(idx.parent(), idx.row(), idx.row());
+ m_groupHash.remove(idx.row());
+ m_groupMaps.removeAt(idx.row());
+ m_parentCreateList.removeAt(idx.internalId());
+ endRemoveRows();
- //TODO: only true if all data could be unset.
- return true;
+ // TODO: only true if all data could be unset.
+ return true;
}
-bool
-QtGroupingProxy::hasChildren( const QModelIndex &parent ) const
-{
- if( !parent.isValid() ) {
- return true;
- }
+bool QtGroupingProxy::hasChildren(const QModelIndex& parent) const {
+ if (!parent.isValid()) {
+ return true;
+ }
- if( isGroup( parent ) ) {
- return !m_groupHash.value( parent.row() ).isEmpty();
- }
+ if (isGroup(parent)) {
+ return !m_groupHash.value(parent.row()).isEmpty();
+ }
- return sourceModel()->hasChildren( mapToSource( parent ) );
+ return sourceModel()->hasChildren(mapToSource(parent));
}
-bool
-QtGroupingProxy::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
-{
- QModelIndex idx = index(row, column, parent);
- if (isGroup(idx)) {
- QList<int> childRows = m_groupHash.value(idx.row());
- int max = *std::max_element(childRows.begin(), childRows.end());
+bool QtGroupingProxy::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column,
+ const QModelIndex& parent) {
+ QModelIndex idx = index(row, column, parent);
+ if (isGroup(idx)) {
+ QList<int> childRows = m_groupHash.value(idx.row());
+ int max = *std::max_element(childRows.begin(), childRows.end());
- QModelIndex newIdx = mapToSource(index(max, column, idx));
- return sourceModel()->dropMimeData(data, action, max, column, newIdx);
- } else {
- if (row == -1) {
- return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
+ QModelIndex newIdx = mapToSource(index(max, column, idx));
+ return sourceModel()->dropMimeData(data, action, max, column, newIdx);
} else {
- QModelIndex idx = mapToSource(index(row, column, parent));
- return sourceModel()->dropMimeData(data, action, idx.row(), idx.column(), idx.parent());
+ if (row == -1) {
+ return sourceModel()->dropMimeData(data, action, -1, -1, mapToSource(parent));
+ } else {
+ QModelIndex idx = mapToSource(index(row, column, parent));
+ return sourceModel()->dropMimeData(data, action, idx.row(), idx.column(), idx.parent());
+ }
}
- }
}
-void
-QtGroupingProxy::modelRowsAboutToBeInserted( const QModelIndex &parent, int start, int end )
-{
- if( parent != m_rootNode )
- {
- //an item will be added to an original index, remap and pass it on
- // qDebug() << parent;
- QModelIndex proxyParent = mapFromSource( parent );
- // qDebug() << proxyParent;
- beginInsertRows( proxyParent, start, end );
- }
+void QtGroupingProxy::modelRowsAboutToBeInserted(const QModelIndex& parent, int start, int end) {
+ if (parent != m_rootNode) {
+ // an item will be added to an original index, remap and pass it on
+ // qDebug() << parent;
+ QModelIndex proxyParent = mapFromSource(parent);
+ // qDebug() << proxyParent;
+ beginInsertRows(proxyParent, start, end);
+ }
}
-void
-QtGroupingProxy::modelRowsInserted( const QModelIndex &parent, int start, int end )
-{
- if( parent == m_rootNode )
- {
- //top level of the model changed, these new rows need to be put in groups
- for( int modelRow = start; modelRow <= end ; modelRow++ )
- {
- addSourceRow( sourceModel()->index( modelRow, m_groupedColumn, m_rootNode ) );
+void QtGroupingProxy::modelRowsInserted(const QModelIndex& parent, int start, int end) {
+ if (parent == m_rootNode) {
+ // top level of the model changed, these new rows need to be put in groups
+ for (int modelRow = start; modelRow <= end; modelRow++) {
+ addSourceRow(sourceModel()->index(modelRow, m_groupedColumn, m_rootNode));
+ }
+ } else {
+ // an item was added to an original index, remap and pass it on
+ QModelIndex proxyParent = mapFromSource(parent);
+ qDebug() << proxyParent;
+ // beginInsertRows had to be called in modelRowsAboutToBeInserted()
+ endInsertRows();
}
- }
- else
- {
- //an item was added to an original index, remap and pass it on
- QModelIndex proxyParent = mapFromSource( parent );
- qDebug() << proxyParent;
- //beginInsertRows had to be called in modelRowsAboutToBeInserted()
- endInsertRows();
- }
}
-void
-QtGroupingProxy::modelRowsAboutToBeRemoved( const QModelIndex &parent, int start, int end )
-{
- if( parent == m_rootNode )
- {
- QHash<quint32, QList<int> >::const_iterator i;
- //HACK, we are going to call beginRemoveRows() multiple times without
- // endRemoveRows() if a source index is in multiple groups.
- // This can be a problem for some views/proxies, but Q*Views can handle it.
- // TODO: investigate a queue for applying proxy model changes in the correct order
- for( i = m_groupHash.constBegin(); i != m_groupHash.constEnd(); ++i )
- {
- int groupIndex = i.key();
- const QList<int> &groupList = i.value();
- QModelIndex proxyParent = index( groupIndex, 0 );
- foreach( int originalRow, groupList )
- {
- if( originalRow >= start && originalRow <= end )
- {
- int proxyRow = groupList.indexOf( originalRow );
- if( groupIndex == -1 ) //adjust for non-grouped (root level) original items
- proxyRow += m_groupMaps.count();
- //TODO: optimize for continues original rows in the same group
- beginRemoveRows( proxyParent, proxyRow, proxyRow );
+void QtGroupingProxy::modelRowsAboutToBeRemoved(const QModelIndex& parent, int start, int end) {
+ if (parent == m_rootNode) {
+ QHash<quint32, QList<int>>::const_iterator i;
+ // HACK, we are going to call beginRemoveRows() multiple times without
+ // endRemoveRows() if a source index is in multiple groups.
+ // This can be a problem for some views/proxies, but Q*Views can handle it.
+ // TODO: investigate a queue for applying proxy model changes in the correct order
+ for (i = m_groupHash.constBegin(); i != m_groupHash.constEnd(); ++i) {
+ int groupIndex = i.key();
+ const QList<int>& groupList = i.value();
+ QModelIndex proxyParent = index(groupIndex, 0);
+ foreach (int originalRow, groupList) {
+ if (originalRow >= start && originalRow <= end) {
+ int proxyRow = groupList.indexOf(originalRow);
+ if (groupIndex == -1) // adjust for non-grouped (root level) original items
+ proxyRow += m_groupMaps.count();
+ // TODO: optimize for continues original rows in the same group
+ beginRemoveRows(proxyParent, proxyRow, proxyRow);
+ }
+ }
}
- }
+ } else {
+ // child item(s) of an original item will be removed, remap and pass it on
+ // qDebug() << parent;
+ QModelIndex proxyParent = mapFromSource(parent);
+ // qDebug() << proxyParent;
+ beginRemoveRows(proxyParent, start, end);
}
- }
- else
- {
- //child item(s) of an original item will be removed, remap and pass it on
- // qDebug() << parent;
- QModelIndex proxyParent = mapFromSource( parent );
- // qDebug() << proxyParent;
- beginRemoveRows( proxyParent, start, end );
- }
}
-void
-QtGroupingProxy::modelRowsRemoved( const QModelIndex &parent, int start, int end )
-{
- if( parent == m_rootNode )
- {
- //TODO: can be optimised by iterating over m_groupHash and checking start <= r < end
+void QtGroupingProxy::modelRowsRemoved(const QModelIndex& parent, int start, int end) {
+ if (parent == m_rootNode) {
+ // TODO: can be optimised by iterating over m_groupHash and checking start <= r < end
- //rather than increasing i we change the stored sourceRows in-place and reuse argument start
- //X-times (where X = end - start).
- for( int i = start; i <= end; i++ )
- {
- //HACK: we are going to iterate the hash in reverse so calls to endRemoveRows()
- // are matched up with the beginRemoveRows() in modelRowsAboutToBeRemoved()
- //NOTE: easier to do reverse with java style iterator
- QMutableHashIterator<quint32, QList<int> > iter( m_groupHash );
- iter.toBack();
- while( iter.hasPrevious() )
- {
- iter.previous();
- int groupIndex = iter.key();
- //has to be a modifiable reference for remove and replace operations
- QList<int> &groupList = iter.value();
- int rowIndex = groupList.indexOf( start );
- if( rowIndex != -1 )
- {
- QModelIndex proxyParent = index( groupIndex, 0 );
- groupList.removeAt( rowIndex );
- }
- //Now decrement all source rows that are after the removed row
- for( int j = 0; j < groupList.count(); j++ )
- {
- int sourceRow = groupList.at( j );
- if( sourceRow > start )
- groupList.replace( j, sourceRow-1 );
+ // rather than increasing i we change the stored sourceRows in-place and reuse argument start
+ // X-times (where X = end - start).
+ for (int i = start; i <= end; i++) {
+ // HACK: we are going to iterate the hash in reverse so calls to endRemoveRows()
+ // are matched up with the beginRemoveRows() in modelRowsAboutToBeRemoved()
+ // NOTE: easier to do reverse with java style iterator
+ QMutableHashIterator<quint32, QList<int>> iter(m_groupHash);
+ iter.toBack();
+ while (iter.hasPrevious()) {
+ iter.previous();
+ int groupIndex = iter.key();
+ // has to be a modifiable reference for remove and replace operations
+ QList<int>& groupList = iter.value();
+ int rowIndex = groupList.indexOf(start);
+ if (rowIndex != -1) {
+ QModelIndex proxyParent = index(groupIndex, 0);
+ groupList.removeAt(rowIndex);
+ }
+ // Now decrement all source rows that are after the removed row
+ for (int j = 0; j < groupList.count(); j++) {
+ int sourceRow = groupList.at(j);
+ if (sourceRow > start)
+ groupList.replace(j, sourceRow - 1);
+ }
+ if (rowIndex != -1)
+ endRemoveRows(); // end remove operation only after group was updated.
+ }
}
- if( rowIndex != -1)
- endRemoveRows(); //end remove operation only after group was updated.
- }
- }
- return;
- }
+ return;
+ }
- //beginRemoveRows had to be called in modelRowsAboutToBeRemoved();
- endRemoveRows();
+ // beginRemoveRows had to be called in modelRowsAboutToBeRemoved();
+ endRemoveRows();
}
-void
-QtGroupingProxy::resetModel()
-{
- buildTree();
-}
+void QtGroupingProxy::resetModel() { buildTree(); }
-void
-QtGroupingProxy::modelDataChanged( const QModelIndex &topLeft, const QModelIndex &bottomRight )
-{
- //TODO: need to look in the groupedColumn and see if it changed and changed grouping accordingly
- QModelIndex proxyTopLeft = mapFromSource( topLeft );
- if( !proxyTopLeft.isValid() )
- return;
+void QtGroupingProxy::modelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight) {
+ // TODO: need to look in the groupedColumn and see if it changed and changed grouping accordingly
+ QModelIndex proxyTopLeft = mapFromSource(topLeft);
+ if (!proxyTopLeft.isValid())
+ return;
- if( topLeft == bottomRight )
- {
- emit dataChanged( proxyTopLeft, proxyTopLeft );
- }
- else
- {
- QModelIndex proxyBottomRight = mapFromSource( bottomRight );
- emit dataChanged( proxyTopLeft, proxyBottomRight );
- }
+ if (topLeft == bottomRight) {
+ emit dataChanged(proxyTopLeft, proxyTopLeft);
+ } else {
+ QModelIndex proxyBottomRight = mapFromSource(bottomRight);
+ emit dataChanged(proxyTopLeft, proxyBottomRight);
+ }
}
-bool
-QtGroupingProxy::isAGroupSelected( const QModelIndexList& list ) const
-{
- foreach( const QModelIndex &index, list )
- {
- if( isGroup( index ) )
- return true;
- }
- return false;
+bool QtGroupingProxy::isAGroupSelected(const QModelIndexList& list) const {
+ foreach (const QModelIndex& index, list) {
+ if (isGroup(index))
+ return true;
+ }
+ return false;
}
-void
-QtGroupingProxy::dumpGroups() const
-{
- qDebug() << "m_groupHash: ";
- for( int groupIndex = -1; groupIndex < m_groupHash.keys().count() - 1; groupIndex++ )
- {
- qDebug() << groupIndex << " : " << m_groupHash.value( groupIndex );
- }
+void QtGroupingProxy::dumpGroups() const {
+ qDebug() << "m_groupHash: ";
+ for (int groupIndex = -1; groupIndex < m_groupHash.keys().count() - 1; groupIndex++) {
+ qDebug() << groupIndex << " : " << m_groupHash.value(groupIndex);
+ }
- qDebug() << "m_groupMaps: ";
- for( int groupIndex = 0; groupIndex < m_groupMaps.count(); groupIndex++ )
- qDebug() << m_groupMaps[groupIndex] << ": " << m_groupHash.value( groupIndex );
- qDebug() << m_groupHash.value( std::numeric_limits<quint32>::max() );
+ qDebug() << "m_groupMaps: ";
+ for (int groupIndex = 0; groupIndex < m_groupMaps.count(); groupIndex++)
+ qDebug() << m_groupMaps[groupIndex] << ": " << m_groupHash.value(groupIndex);
+ qDebug() << m_groupHash.value(std::numeric_limits<quint32>::max());
}
-
-void QtGroupingProxy::expanded(const QModelIndex &index)
-{
- m_expandedItems.insert(index.data(Qt::UserRole).toString());
+void QtGroupingProxy::expanded(const QModelIndex& index) {
+ m_expandedItems.insert(index.data(Qt::UserRole).toString());
}
-void QtGroupingProxy::collapsed(const QModelIndex &index)
-{
- m_expandedItems.remove(index.data(Qt::UserRole).toString());
+void QtGroupingProxy::collapsed(const QModelIndex& index) {
+ m_expandedItems.remove(index.data(Qt::UserRole).toString());
}
|
