Logo Search packages:      
Sourcecode: webissues version File versions  Download package

tableitemmodel.cpp

/**************************************************************************
* This file is part of the WebIssues program
* Copyright (C) 2006 Michał Męciński
* Copyright (C) 2007 WebIssues Team
*
* This program is free software\n{\n} you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation\n{\n} either version 2 of the License, or
* (at your option) any later version.
**************************************************************************/

#include "tableitemmodel.h"

#include <QPixmap>

#include "data/rdb/tableiterators.h"
#include "abstracttablemodel.h"
#include "abstractrowfilter.h"
#include "tablemodelshelper.h"

using namespace WebIssues;

00023 TableItemModel::TableItemModel( QObject* parent ) : QAbstractItemModel( parent ),
    m_filter( NULL ),
    m_uniqueIndex( NULL ),
    m_foreignIndex( NULL ),
    m_sortColumn( (Column)-1 ),
    m_sortOrder( Qt::AscendingOrder ),
    m_totalCount( 0 )
{
}

00033 TableItemModel::~TableItemModel()
{
}

00037 void TableItemModel::setColumns( const QList<Column>& columns )
{
    m_columns = columns;

    reset();
}

00044 void TableItemModel::setRowFilter( AbstractRowFilter* filter )
{
    m_filter = filter;

    connect( filter, SIGNAL( conditionsChanged() ), this, SLOT( updateTable() ) );

    if ( m_uniqueIndex || m_foreignIndex )
        updateTable();
}

00054 void TableItemModel::setRootTableModel( AbstractTableModel* model, const RDB::UniqueIndexBase* index )
{
    attachTableModel( model );

    m_uniqueIndex = index;
    m_foreignIndex = NULL;

    buildAllIndexes();

    reset();
}

00066 void TableItemModel::setRootTableModel( AbstractTableModel* model, const RDB::ForeignIndexBase* index, int parentId )
{
    attachTableModel( model );

    m_uniqueIndex = NULL;
    m_foreignIndex = index;
    m_parentId = parentId;

    buildAllIndexes();

    reset();
}

00079 AbstractTableModel* TableItemModel::rootTableModel() const
{
    return m_models.first();
}

00084 void TableItemModel::addChildTableModel( AbstractTableModel* model, const RDB::ForeignIndexBase* index )
{
    attachTableModel( model );

    m_childIndexes.append( index );

    for ( int i = 0; i < m_itemGroups.count(); i++ ) {
        if ( m_itemGroups.at( i ).m_level == m_childIndexes.count() - 1 )
            buildChildIndexes( i );
    }

    reset();
}

int TableItemModel::columnCount( const QModelIndex& parent ) const
{
    return m_columns.count();
}

QVariant TableItemModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
    if ( orientation == Qt::Horizontal && role == Qt::DisplayRole )
        return TableModelsHelper::columnName( m_columns.at( section ) );

    if ( orientation == Qt::Horizontal && role == ColumnRole )
        return (int)m_columns.at( section );

    return QVariant();
}

int TableItemModel::rowCount( const QModelIndex& parent ) const
{
    if ( !parent.isValid() )
        return m_itemGroups.first().m_items.count();

    int group = parent.internalId();

    int childGroup = m_itemGroups.at( group ).m_items.at( parent.row() ).m_childGroup;
    if ( childGroup < 0 )
        return 0;

    return m_itemGroups.at( childGroup ).m_items.count();
}

QModelIndex TableItemModel::index( int row, int column, const QModelIndex& parent ) const
{
    if ( !parent.isValid() )
        return createIndex( row, column, 0 );

    int group = parent.internalId();

    int childGroup = m_itemGroups.at( group ).m_items.at( parent.row() ).m_childGroup;
    if ( childGroup < 0 )
        return QModelIndex();

    return createIndex( row, column, childGroup );
}

QModelIndex TableItemModel::parent( const QModelIndex& index ) const
{
    if ( !index.isValid() )
        return QModelIndex();

    int group = index.internalId();

    int level = m_itemGroups.at( group ).m_level;

    if ( level == 0 )
        return QModelIndex();

    for ( int i = 0; i < m_itemGroups.count(); i++ ) {
        if ( m_itemGroups.at( i ).m_level == level - 1 ) {
            for ( int j = 0; j < m_itemGroups.at( i ).m_items.count(); j++ ) {
                if ( m_itemGroups.at( i ).m_items.at( j ).m_childGroup == group )
                    return createIndex( j, 0, i );
            }
        }
    }

    return QModelIndex();
}

QVariant TableItemModel::data( const QModelIndex& index, int role ) const
{
    if ( !index.isValid() )
        return QVariant();

    int group = index.internalId();

    int id = m_itemGroups.at( group ).m_items.at( index.row() ).m_id;
    int level = m_itemGroups.at( group ).m_level;

    if ( role == Qt::DisplayRole )
        return m_models.at( level )->text( id, m_columns.at( index.column() ) );

    if ( role == Qt::DecorationRole && m_columns.at( index.column() ) == Column_Name )
        return m_models.at( level )->icon( id );

    if ( role == Qt::ToolTipRole )
        return m_models.at( level )->toolTip( id );

    if ( role == RowIdRole )
        return id;

    if ( role == LevelRole )
        return level;

    return QVariant();
}

void TableItemModel::sort( int column, Qt::SortOrder order )
{
    if ( m_sortColumn == m_columns.at( column ) && m_sortOrder == order )
        return;

    m_sortColumn = m_columns.at( column );
    m_sortOrder = order;

    sortAllGroups();
}

void TableItemModel::attachTableModel( AbstractTableModel* model )
{
    connect( model, SIGNAL( tableChanged() ), this, SLOT( updateTable() ) );
    connect( model, SIGNAL( rowsChanged() ), this, SLOT( updateRows() ) );
    connect( model, SIGNAL( rowChanged( int ) ), this, SLOT( updateRow( int ) ) );

    m_models.append( model );
}

void TableItemModel::buildAllIndexes()
{
    m_itemGroups.clear();

    buildRootIndex();

    for ( int i = 0; i < m_itemGroups.count(); i++ )
        buildChildIndexes( i );
}

void TableItemModel::buildRootIndex()
{
    m_totalCount = 0;

    addGroup( 0 );

    if ( m_uniqueIndex ) {
        RDB::IndexConstIteratorBase it( m_uniqueIndex );
        while ( it.next() ) {
            m_totalCount++;
            int id = it.get()->key( 0 );
            if ( m_filter && !m_filter->filterRow( id ) )
                continue;
            addItemToGroup( 0, id );
        }
    } else if ( m_foreignIndex ) {
        RDB::ForeignConstIteratorBase it( m_foreignIndex, m_parentId );
        while ( it.next() ) {
            m_totalCount++;
            int id = it.get()->key( 0 );
            if ( m_filter && !m_filter->filterRow( id ) )
                continue;
            addItemToGroup( 0, id );
        }
    }

    sortGroup( 0 );
}

void TableItemModel::buildChildIndexes( int group )
{
    int level = m_itemGroups.at( group ).m_level;

    if ( level >= m_childIndexes.count() )
        return;

    for ( int i = 0; i < m_itemGroups.at( group ).m_items.count(); i++ ) {
        int childGroup = -1;

        RDB::ForeignConstIteratorBase it( m_childIndexes.at( level ), m_itemGroups.at( group ).m_items.at( i ).m_id );
        while ( it.next() ) {
            if ( childGroup < 0 ) {
                childGroup = addGroup( level + 1 );
                m_itemGroups[ group ].m_items[ i ].m_childGroup = childGroup;
            }
            addItemToGroup( childGroup, it.get()->key( 0 ) );
        }

        if ( childGroup >= 0 )
            sortGroup( childGroup );
    }
}

int TableItemModel::addGroup( int level )
{
    ItemGroup group;
    group.m_level = level;
    m_itemGroups.append( group );

    return m_itemGroups.count() - 1;
}

void TableItemModel::addItemToGroup( int group, int id )
{
    Item item;
    item.m_id = id;
    item.m_childGroup = -1;
    m_itemGroups[ group ].m_items.append( item );
}

void TableItemModel::sortAllGroups()
{
    if ( m_sortOrder < 0 )
        return;

    emit layoutAboutToBeChanged();

    QModelIndexList oldIndexes = persistentIndexList();

    QList<CellIndex> cellIndexes;
    for ( int i = 0; i < oldIndexes.count(); i++ )
        cellIndexes.append( cellAt( oldIndexes.at( i ) ) );

    for ( int i = 0; i < m_itemGroups.count(); i++ )
        sortGroup( i );

    QModelIndexList newIndexes;
    for ( int i = 0; i < cellIndexes.count(); i++ )
        newIndexes.append( findCell( cellIndexes.at( i ) ) );

    changePersistentIndexList( oldIndexes, newIndexes );

    emit layoutChanged();
}

void TableItemModel::sortGroup( int group )
{
    if ( m_sortOrder < 0 )
        return;

    AbstractTableModel* model = m_models.at( m_itemGroups.at( group ).m_level );

    qStableSort( m_itemGroups[ group ].m_items.begin(), m_itemGroups[ group ].m_items.end(),
        CompareItems( model, m_sortColumn, m_sortOrder ) );
}

void TableItemModel::updateTable()
{
    emit layoutAboutToBeChanged();

    QModelIndexList oldIndexes = persistentIndexList();

    QList<CellIndex> cellIndexes;
    for ( int i = 0; i < oldIndexes.count(); i++ )
        cellIndexes.append( cellAt( oldIndexes.at( i ) ) );

    buildAllIndexes();

    QModelIndexList newIndexes;
    for ( int i = 0; i < cellIndexes.count(); i++ )
        newIndexes.append( findCell( cellIndexes.at( i ) ) );

    changePersistentIndexList( oldIndexes, newIndexes );

    emit layoutChanged();
}

void TableItemModel::updateRows()
{
    int level = m_models.indexOf( (AbstractTableModel*)sender() );
    if ( level < 0 )
        return;

    for ( int i = 0; i < m_itemGroups.count(); i++ ) {
        if ( m_itemGroups.at( i ).m_level == level ) {
            QModelIndex from = createIndex( 0, 0, i );
            QModelIndex to = createIndex( m_itemGroups.at( i ).m_items.count() - 1, m_columns.count() - 1, i );
            emit dataChanged( from, to );
        }
    }
}

void TableItemModel::updateRow( int id )
{
    int level = m_models.indexOf( (AbstractTableModel*)sender() );
    if ( level < 0 )
        return;

    CellIndex cell;
    cell.m_level = level;
    cell.m_id = id;
    cell.m_column = 0;
    QModelIndex index = findCell( cell );

    if ( index.isValid() )
        emit dataChanged( index, createIndex( index.row(), m_columns.count() - 1, (quint32)index.internalId() ) );
    else
        updateTable();
}

TableItemModel::CellIndex TableItemModel::cellAt( const QModelIndex& index )
{
    CellIndex cell;

    if ( !index.isValid() ) {
        cell.m_id = 0;
        cell.m_level = -1;
        cell.m_column = 0;
        return cell;
    }

    int group = index.internalId();

    cell.m_id = m_itemGroups.at( group ).m_items.at( index.row() ).m_id;
    cell.m_level = m_itemGroups.at( group ).m_level;
    cell.m_column = index.column();

    return cell;
}

QModelIndex TableItemModel::findCell( const CellIndex& cell )
{
    if ( cell.m_level < 0 )
        return QModelIndex();

    for ( int i = 0; i < m_itemGroups.count(); i++ ) {
        if ( m_itemGroups.at( i ).m_level == cell.m_level ) {
            for ( int j = 0; j < m_itemGroups.at( i ).m_items.count(); j++ ) {
                if ( m_itemGroups.at( i ).m_items.at( j ).m_id == cell.m_id )
                    return createIndex( j, cell.m_column, i );
            }
        }
    }

    return QModelIndex();
}

TableItemModel::CompareItems::CompareItems( AbstractTableModel* model, Column column, Qt::SortOrder order ) :
    m_model( model ),
    m_column( column ),
    m_order( order )
{
}

bool TableItemModel::CompareItems::operator()( const TableItemModel::Item& item1, const TableItemModel::Item& item2 )
{
    int result = m_model->compare( item1.m_id, item2.m_id, m_column );
    if ( m_order == Qt::AscendingOrder )
        return result < 0;
    else
        return result > 0;
}

#include "tableitemmodel.moc"

Generated by  Doxygen 1.6.0   Back to index