PDA

View Full Version : TransposeProxy-based filtering problem



mclark
9th June 2010, 16:16
Greetings,

Using the TransposeProxy example as a template I've subclassed QSortFilterProxyModel to display table-based model data in both QTableView and QTreeView widgets. The structure of the model is fixed since it is provided by someone else. (I'm using Qt 4.6.2 on a Win XP system.)

QTreeView problem: I want to display a subset of the model header strings in a 'Property' column and the corresponding data in a 'Value' column. The data in the model, for example, is 1 row, 25 entries but I only want to display columns 16-24 in the QTreeView. What I am seeing is ALL of the headers (indexes 0-24) in the tree and NO data values.

MODEL
+---+---+---+-...-+----+-...-+----+
| 0 | 1 | 2 | ... | 16 | ... | 24 | HEADER
+---+---+---+-...-+----+-...-+----+
| a | b | c | ... | aa | ... | ii | DATA
+---+---+---+-...-+----+-...-+----+

So, I have two problems:

How to display only a subset of the model.
How to get the data to display.

I've overridden the filterAcceptsRow() and filterAcceptsColumn() functions in my proxy. The row appears to be filtered correctly and the columns appear to reject indexes 0-15. But, headers 0-15 still appear. Again, no data values appear.

Clearly I don't fully understand how to handle the proxy functions to deal with this situation. Might this be a problem with the mapToSource() override? Anyone have suggestions?


PropInspectProxyModel::PropInspectProxyModel( const DCID& dcid,
const CID& cid,
QObject* pObject )
: QSortFilterProxyModel( pObject )
, m_dcid( dcid )
, m_cid( cid )
, m_nNumProps( 10 )//TODO: make this a parameter
{
// Set this property to true to have the proxy model re-filter whenever
// the contents of the source model change.
setDynamicSortFilter( true );

//TODO: why doesn't setting the headers here work? No headers appear at all!
setHeaderData( 0, Qt::Horizontal, QVariant( "Property" ), Qt::DisplayRole );
setHeaderData( 1, Qt::Horizontal, QVariant( "Value" ), Qt::DisplayRole );

m_dcidCol = global.worldModelHelper->findFirstDCIDCol( m_dcid );
m_nMaxColIdx = m_dcidCol + m_nNumProps;
}

QModelIndex PropInspectProxyModel::mapToSource( const QModelIndex& proxyIndex ) const
{
return sourceModel()->index( proxyIndex.column(), proxyIndex.row() );
}

bool PropInspectProxyModel::filterAcceptsRow( int source_row,
const QModelIndex& source_parent ) const
{
QStandardItemModel* pModel = qobject_cast<QStandardItemModel*>(sourceModel());
QStandardItem* pStdItem = pModel->item( source_row );

if ( pStdItem != NULL )
{
CID cid;

ConcertItemAdditionC* pItem = dynamic_cast<ConcertItemAdditionC*>( pStdItem );
if ( pItem != NULL )
{
cid = pItem->getCID();

// Filter on CID
if ( cid == m_cid )
return true;
}
}

return false;
}

bool PropInspectProxyModel::filterAcceptsColumn( int source_column,
const QModelIndex& source_parent ) const
{
if ( (source_column >= m_dcidCol) && (source_column <= m_nMaxColIdx) )
return true;

return false;
}

numbat
10th June 2010, 10:20
You don't need the mapToSource. Get rid of it.

mclark
10th June 2010, 15:30
I think it's necessary, without mapToSource() the program crashes when setting the model in the QTreeView.


PropInspectProxyModel* proxyModel =
new PropInspectProxyModel( dcid, cid );
if ( proxyModel == NULL )
{
// report error
return;
}

proxyModel->setSourceModel( m_pSourceModel );
m_pPropTree->setModel( proxyModel ); // crashes here!

mclark
10th June 2010, 20:36
I have been able to remove the unwanted header values from the rows (0-15) in the tree view. Unforunately those rows remain empty instead of being filled with the filtered values.

I have also found that the data() function can get both the header values AND data values.

QVariant PropInspectProxyModel::data( const QModelIndex& index, int role ) const
{
QModelIndex source_index = mapToSource( index );
if ( index.isValid() && !source_index.isValid() )
return QVariant();

///////////////////////////////////////////////////////////////////////////
// How do I know when to get the header data vs. getting the data values???

// Get the Property header string
QVariant vHdr = sourceModel()->headerData( index.row(), Qt::Horizontal, role );

// Get the data values
QVariant v = sourceModel()->data( source_index, role );

return v;
}Two unresolved issues remain:

How can I get my headers to fill rows 0-9 instead of 16-25?
How do I know when to get header values or data values in the data() override function?
Examples

Headers4765
Data4764

ChrisW67
11th June 2010, 02:49
What does rowCount() on the proxy model return? It should be the number of rows for the given parent index left after the filter is applied. Similarly for the columnCount(). If this is not the case then look at your filter implementations. Is there a hierarchy in the model... are all parent model indexes invalid or not?

When a request is made on the filtered side of the model via data() you need to map the row number to the base model row e.g. proxy row 0 maps to row 16 in the source, 1 to 17, etc. mapToSource() should do this and mapFromSource() should do the inverse. I would have thought the default proxy implementation does this for you and you should not need to reimplement these.

The view should never call data() to retrieve headers, that's what headerData() is for. The proxy default implementation should also be returning the header data from the base model for rows/columns that get past the filter.