Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Sorting Breaks the Selection When a New Column is Added to the SubClassed Model



  • Hi all,

    We are using a custom QSortFilterProxyModel. We have mapToSource and mapFromSource methods. Before sorting there was no problem about adding new columns to the proxy model.

    Before proxy the codes like below:

    QModelIndex ProxyModel::index(int in_row, int in_column, const QModelIndex &in_parent) const
    {
        Q_UNUSED(in_parent);
    
        if (0 > in_row || 0 > in_column || in_row > this->rowCount() || in_column > this->columnCount())
            return QModelIndex();
    
        return createIndex(in_row, in_column);
    }
    QModelIndex ProxyModel::parent(const QModelIndex &in_child) const
    {
        Q_UNUSED(in_child);
        return QModelIndex();
    }
    QModelIndex ProxyModel::mapToSource(const QModelIndex &in_proxy_index) const
    {
        if (false == in_proxy_index.isValid())
            return QModelIndex();
    
        Q_ASSERT(this == in_proxy_index.model());
    
        if(0 == m_proxy_column_indexes.size() && 0 == m_proxy_row_indexes.size())
        {
            return sourceModel()->index(in_proxy_index.row(), in_proxy_index.column());
        }
        else
        {
            int added_column_indexes = 0;
            for (int proxy_column_index : m_proxy_column_indexes)
            {
                if(in_proxy_index.column() == proxy_column_index)
                {
                    return QModelIndex();
                }
                else if(in_proxy_index.column() > proxy_column_index)
                {
                    added_column_indexes++;
                }
                else
                {
                    break;
                }
            }
            int added_row_indexes = 0;
            for (int proxy_row_index : m_proxy_row_indexes)
            {
                if(in_proxy_index.row() == proxy_row_index)
                {
                    return QModelIndex();
                }
                else if(in_proxy_index.row() > proxy_row_index)
                {
                    added_row_indexes++;
                }
                else
                {
                    break;
                }
            }
            return sourceModel()->index(in_proxy_index.row() - added_row_indexes, in_proxy_index.column() - added_column_indexes);
        }
    }
    QModelIndex ProxyModel::mapFromSource(const QModelIndex &in_source_index) const
    {
        if (false == in_source_index.isValid())
            return QModelIndex();
    
        if(0 == m_proxy_column_indexes.size() && 0 == m_proxy_row_indexes.size())
        {
            return index(in_source_index.row(), in_source_index.column());
        }
        else
        {
            int added_column_indexes = 0;
            for (int proxy_column_index : m_proxy_column_indexes)
            {
                if(in_source_index.column() > proxy_column_index)
                {
                    added_column_indexes++;
                }
                else
                {
                    break;
                }
            }
            int added_row_indexes = 0;
            for (int proxy_row_index : m_proxy_row_indexes)
            {
                if(in_source_index.row() > proxy_row_index)
                {
                    added_row_indexes++;
                }
                else
                {
                    break;
                }
            }
            return index(in_source_index.row() + added_row_indexes, in_source_index.column() + added_column_indexes);
        }
    }
    
    void ProxyModel::insertProxyColumn(const int in_column_index)
    {
        beginInsertColumns(QModelIndex(),in_column_index, in_column_index);
        if (false == (0 > in_column_index || in_column_index >= columnCount()))
        {
            m_proxy_column_indexes.append(in_column_index);
            std::sort(m_proxy_column_indexes.begin(),m_proxy_column_indexes.end(),std::less<int>());
        }
        endInsertColumns();
    }
    

    After changes to apply sorting:
    We deleted index and parent and change the return of mapping methods like below (our index and parent methods gives an error):
    2020-08-05 14_01_46-ProxyModel.cpp (Ui_WidgetsLib_src_TableView @ AVLDriveCore) - Qt Creator.png

    return QSortFilterProxyModel::mapToSource(index(in_proxy_index.row() - added_row_indexes, in_proxy_index.column() - added_column_indexes));
    
    return QSortFilterProxyModel::mapFromSource(sourceModel()->index(in_source_index.row() + added_row_indexes, in_source_index.column() + added_column_indexes));
    

    If we do not use parent class'es mapping methods we cannot sort our custom model. However, this implementation breaks selection model of tableview and also some columns disappears at the end. Can you help us to solve the problem


  • Lifetime Qt Champion

    Hi,

    I think it would be simpler to have one proxy that adds your special columns and on top of that one use QSortFilterProxyModel. This will avoid trying to do two different things with the same class.



  • @SGaist but it means I should have 2 proxy subclass, which is not a good solution. I know that If I gave the this model as a soruce to another qsortfilterproxymodel I can sort without side effects, but in this case we have use setModel() method of qtableview subclass. At first I coded it, but there should be another way to do it. This way looks like cheating a little.

    Also, the custom proxymodel is used to do everything inside the tableview since we do not want to change anything inside the source. You can think our proxymodel is an internal mdel inside the tableview



  • @DzCode said in Sorting Breaks the Selection When a New Column is Added to the SubClassed Model:

    @SGaist but it means I should have 2 proxy subclass, which is not a good solution
    This way looks like cheating a little.

    Why do you say that? Having two separate proxies which do two different things separately, as @SGaist suggests, can be a very good way of approaching things....



  • @JonB We have checkboxes and also we have colorboxes and colordialogs with item delegate. If I use another model, after sort, when I check a chekbox the colorbox in a different row is opened. This can be solved.

    But we have dropdown in the custom model. For example there are some special buttons in some rows which opens dropdown data or closes. Implementation of this will be hard



  • I am still looking for a better solution for this problem to make it with only one proxy model


Log in to reply