From de27ab391f5c56db9532e7cbc32145d21e5df97c Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 4 Apr 2013 21:49:44 +0200 Subject: - creating mods from overwrite - moving files from overwrite to mods - offline mode - several fixes to the grouping system - fix to "duplicate translation" errors --- src/qtgroupingproxy.cpp | 187 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 155 insertions(+), 32 deletions(-) (limited to 'src/qtgroupingproxy.cpp') diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp index 95a4aad0..4e066f65 100644 --- a/src/qtgroupingproxy.cpp +++ b/src/qtgroupingproxy.cpp @@ -14,7 +14,7 @@ * this program. If not, see . * ****************************************************************************************/ -// Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord +// Modifications 2013-03-27 to 2013-03-29 by Sebastian Herbord #include "QtGroupingProxy.h" @@ -31,11 +31,12 @@ \ingroup model-view */ -QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, Qt::ItemDataRole groupedRole, unsigned int flags ) +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 ); @@ -104,7 +105,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx ) i.next(); int role = i.key(); QVariant variant = i.value(); - qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; + // qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant; if ( variant.type() == QVariant::List ) { //a list of variants get's expanded to multiple rows @@ -171,7 +172,32 @@ QtGroupingProxy::buildTree() //dumpGroups(); if (m_flags & FLAG_NOSINGLE) { + // awkward: flatten single-item groups as a post-processing steps. + int currentKey = 0; + quint32 quint32max = std::numeric_limits::max(); + std::vector rmgroups; + + QHash > temp; + + for (auto iter = m_groupHash.begin(); iter != m_groupHash.end(); ++iter) { + if ((iter.key() == quint32max) || + (iter->count() == 1)) { + temp[quint32max].append(iter.value()); + if (iter.key() != quint32max) { + rmgroups.push_back(iter.key()); + } + } else { + temp[currentKey++] = *iter; + } + } + m_groupHash = temp; + + // second loop is necessary because qt containers can't be iterated from end to + // removing by index from begin to end is ugly + for (auto iter = rmgroups.rbegin(); iter != rmgroups.rend(); ++iter) { + m_groupMaps.removeAt(*iter); + } } endResetModel(); @@ -191,6 +217,7 @@ QtGroupingProxy::addSourceRow( const QModelIndex &idx ) QList updatedGroups; QList groupData = belongsTo( idx ); + //an empty list here means it's supposed to go in root. if( groupData.isEmpty() ) { @@ -346,7 +373,6 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const if( !index.isValid() ) { //the number of top level groups + the number of non-grouped items - qDebug("groups: %d - ungrouped: %d", m_groupMaps.count(), m_groupHash.value(std::numeric_limits::max()).count()); int rows = m_groupMaps.count() + m_groupHash.value( std::numeric_limits::max() ).count(); //qDebug() << rows << " in root group"; return rows; @@ -359,12 +385,12 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const 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; } - - QModelIndex originalIndex = mapToSource( index ); - int rowCount = sourceModel()->rowCount( originalIndex ); - //qDebug() << "original item: rowCount == " << rowCount; - return rowCount; } int @@ -379,6 +405,44 @@ QtGroupingProxy::columnCount( const QModelIndex &index ) const 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(); + } + + // 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; + } + } + return result; +} + + +static QVariant variantMin(const QVariantList &variants) +{ + QVariant result = variants.first(); + foreach (const QVariant &iter, variants) { + if (variantLess(iter, result)) { + result = iter; + } + } + return result; +} + + QVariant QtGroupingProxy::data( const QModelIndex &index, int role ) const { @@ -389,18 +453,8 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const int column = index.column(); if( isGroup( index ) ) { - if (column != 0) return QVariant(); - - //qDebug() << __FUNCTION__ << "is a group"; - //use cached or precalculated data - if( m_groupMaps[row][column].contains( Qt::DisplayRole ) ) - { - //qDebug() << "Using cached data"; + if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) { switch (role) { - case Qt::DisplayRole: { - QString value = m_groupMaps[row][column].value( role ).toString(); - return QString("----- %1 -----").arg(value.isEmpty() ? tr("") : value); - } break; case Qt::ForegroundRole: { return QBrush(Qt::gray); } break; @@ -415,13 +469,47 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const 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: { - return QVariant(); + QModelIndex parentIndex = this->index( row, 0, index.parent() ); + if (m_groupHash.value( row ).count() > 0) { + return this->index(0, 0, parentIndex).data(role); + } else { + return QVariant(); + } // 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; @@ -432,6 +520,13 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const 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(); + } + //qDebug() << __FUNCTION__ << "childCount: " << childCount; //Need a parentIndex with column == 0 because only those have children. QModelIndex parentIndex = this->index( row, 0, index.parent() ); @@ -448,19 +543,29 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const ItemData roleMap = m_groupMaps[row].value( column ); foreach( const QVariant &variant, variantsOfChildren ) { - if( roleMap[ role ] != variant ) + if( roleMap[ role ] != variant ) { roleMap.insert( role, variantsOfChildren ); + } } //qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role]; - //only one unique variant? No need to return a list - if( variantsOfChildren.count() == 1 ) - return variantsOfChildren.first(); if( variantsOfChildren.count() == 0 ) return QVariant(); - return variantsOfChildren; + //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; + } break; + } } return mapToSource( index ).data( role ); @@ -612,7 +717,7 @@ QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const //qDebug() << "proxyParent: " << proxyParent; //qDebug() << "proxyRow: " << proxyRow; - return this->index( proxyRow, 0, proxyParent ); + return this->index( proxyRow, idx.column(), proxyParent ); } Qt::ItemFlags @@ -632,10 +737,28 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const if( isGroup( idx ) ) { // dumpGroups(); - // Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable ); - Qt::ItemFlags defaultFlags(Qt::NoItemFlags); + 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 ( checkable ) { + defaultFlags |= Qt::ItemIsUserCheckable; + } + } + //it's possible to have empty groups if( m_groupHash.value( idx.row() ).count() == 0 ) { @@ -658,7 +781,6 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const break; } } - if( groupIsEditable ) return ( defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled ); return defaultFlags; @@ -671,9 +793,9 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const 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; } @@ -736,8 +858,9 @@ QtGroupingProxy::hasChildren( const QModelIndex &parent ) const if( !parent.isValid() ) return true; - if( isGroup( parent ) ) + if( isGroup( parent ) ) { return !m_groupHash.value( parent.row() ).isEmpty(); + } return sourceModel()->hasChildren( mapToSource( parent ) ); } -- cgit v1.3.1