QAbstractItemModel

Изучаем базовые классы QAbstractItemModel и его скрытую часть реализации QAbstractItemModelPrivate. Надо понимать, что это базовые абстрактные классы модели данных первого уровня (то есть первый уровень наследования от QObjectPrivate). 

Надо сказать, что для понимания принципа функционирования связки модель данных и модель представления это не первый в очереди класс для изучения.

class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QAbstractItemModel)

public:
    QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1), roleNames(defaultRoleNames()) {}
    void removePersistentIndexData(QPersistentModelIndexData *data);
    void movePersistentIndexes(QVector indexes, int change, const QModelIndex &parent, Qt::Orientation orientation);
    void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
    void rowsInserted(const QModelIndex &parent, int first, int last);
    void rowsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
    void rowsRemoved(const QModelIndex &parent, int first, int last);
    void columnsAboutToBeInserted(const QModelIndex &parent, int first, int last);
    void columnsInserted(const QModelIndex &parent, int first, int last);
    void columnsAboutToBeRemoved(const QModelIndex &parent, int first, int last);
    void columnsRemoved(const QModelIndex &parent, int first, int last);
    static QAbstractItemModel *staticEmptyModel();
    static bool variantLessThan(const QVariant &v1, const QVariant &v2);

    void itemsAboutToBeMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation);
    void itemsMoved(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
    bool allowMove(const QModelIndex &srcParent, int srcFirst, int srcLast, const QModelIndex &destinationParent, int destinationChild, Qt::Orientation orientation);
    
    inline QModelIndex createIndex(int row, int column, void *data = 0) const {
        return q_func()->createIndex(row, column, data);
    }

    inline QModelIndex createIndex(int row, int column, int id) const {
        return q_func()->createIndex(row, column, id);
    }

    inline bool indexValid(const QModelIndex &index) const {
         return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func());
    }

    inline void invalidatePersistentIndexes() {
        foreach (QPersistentModelIndexData *data, persistent.indexes) {
            data->index = QModelIndex();
            data->model = 0;
        }
        persistent.indexes.clear();
    }

    /*!
      \internal
      clean the QPersistentModelIndex relative to the index if there is one.
      To be used before an index is invalided
      */
    inline void invalidatePersistentIndex(const QModelIndex &index) {
        QHash::iterator it = persistent.indexes.find(index);
        if(it != persistent.indexes.end()) {
            QPersistentModelIndexData *data = *it;
            persistent.indexes.erase(it);
            data->index = QModelIndex();
            data->model = 0;
        }
    }

    struct Change {
        Change() : first(-1), last(-1) {}
        Change(const Change &c) : parent(c.parent), first(c.first), last(c.last), needsAdjust(c.needsAdjust) {}
        Change(const QModelIndex &p, int f, int l) : parent(p), first(f), last(l), needsAdjust(false) {}
        QModelIndex parent;
        int first, last;


        // In cases such as this:
        // - A
        // - B
        // - C
        // - - D
        // - - E
        // - - F
        //
        // If B is moved to above E, C is the source parent in the signal and its row is 2. When the move is
        // completed however, C is at row 1 and there is no row 2 at the same level in the model at all.
        // The QModelIndex is adjusted to correct that in those cases before reporting it though the
        // rowsMoved signal.
        bool needsAdjust;

        bool isValid() { return first >= 0 && last >= 0; }
    };
    QStack changes;

    struct Persistent {
        Persistent() {}
        QHash indexes;
        QStack > moved;
        QStack > invalidated;
        void insertMultiAtEnd(const QModelIndex& key, QPersistentModelIndexData *data);
    } persistent;

    Qt::DropActions supportedDragActions;

    QHash roleNames;
    static const QHash &defaultRoleNames();
};

Мы столкнулись с вплотную с QAbstractItemModel, когда не смогли понять логику вставки второй новой строки в QTableView.

Проблему можно решить через обработку сигнала primeInsert.

QStack<Change> changes; накапливает информацию о вставленных строках